@plexor-dev/claude-code-plugin 0.1.0-beta.3 → 0.1.0-beta.30

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,242 @@
1
+ /**
2
+ * Claude Code Settings Manager
3
+ *
4
+ * Manages ~/.claude/settings.json to enable automatic Plexor routing.
5
+ *
6
+ * KEY DISCOVERY: Claude Code reads settings.json at runtime and the `env` block
7
+ * overrides environment variables. This allows the plugin to redirect ALL Claude
8
+ * Code sessions to Plexor without users manually setting environment variables.
9
+ *
10
+ * Reference: Claude Code v2.0.1+ behavior - settings.json env takes precedence
11
+ */
12
+
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+
16
+ const CLAUDE_DIR = path.join(process.env.HOME || process.env.USERPROFILE || '', '.claude');
17
+ const SETTINGS_PATH = path.join(CLAUDE_DIR, 'settings.json');
18
+
19
+ // Plexor gateway endpoints
20
+ const PLEXOR_STAGING_URL = 'https://staging.api.plexor.dev/gateway/anthropic';
21
+ const PLEXOR_PROD_URL = 'https://api.plexor.dev/gateway/anthropic';
22
+
23
+ class ClaudeSettingsManager {
24
+ constructor() {
25
+ this.settingsPath = SETTINGS_PATH;
26
+ this.claudeDir = CLAUDE_DIR;
27
+ }
28
+
29
+ /**
30
+ * Load current Claude settings
31
+ * @returns {Object} settings object or empty object if not found
32
+ */
33
+ load() {
34
+ try {
35
+ if (!fs.existsSync(this.settingsPath)) {
36
+ return {};
37
+ }
38
+ const data = fs.readFileSync(this.settingsPath, 'utf8');
39
+ return JSON.parse(data);
40
+ } catch (err) {
41
+ // Log unexpected errors (not ENOENT which is handled above)
42
+ if (err.code !== 'ENOENT') {
43
+ console.warn('Warning: Failed to load Claude settings:', err.message);
44
+ }
45
+ return {};
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Save Claude settings
51
+ * @param {Object} settings - settings object to save
52
+ * @returns {boolean} success status
53
+ */
54
+ save(settings) {
55
+ try {
56
+ // Ensure .claude directory exists
57
+ if (!fs.existsSync(this.claudeDir)) {
58
+ fs.mkdirSync(this.claudeDir, { recursive: true });
59
+ }
60
+
61
+ fs.writeFileSync(this.settingsPath, JSON.stringify(settings, null, 2), { mode: 0o600 });
62
+ return true;
63
+ } catch (err) {
64
+ console.error('Failed to save Claude settings:', err.message);
65
+ return false;
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Enable Plexor routing by setting env vars in settings.json
71
+ *
72
+ * This is the KEY mechanism: setting ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN
73
+ * in the env block redirects ALL Claude Code sessions to Plexor automatically.
74
+ *
75
+ * @param {string} apiKey - Plexor API key (plx_*)
76
+ * @param {Object} options - { useStaging: boolean }
77
+ * @returns {boolean} success status
78
+ */
79
+ enablePlexorRouting(apiKey, options = {}) {
80
+ // Default to production. Use useStaging: true for staging keys.
81
+ const { useStaging = false } = options;
82
+ const apiUrl = useStaging ? PLEXOR_STAGING_URL : PLEXOR_PROD_URL;
83
+
84
+ try {
85
+ const settings = this.load();
86
+
87
+ // Initialize env block if doesn't exist
88
+ if (!settings.env) {
89
+ settings.env = {};
90
+ }
91
+
92
+ // Set the magic environment variables
93
+ // ANTHROPIC_AUTH_TOKEN has higher precedence than ANTHROPIC_API_KEY
94
+ settings.env.ANTHROPIC_BASE_URL = apiUrl;
95
+ settings.env.ANTHROPIC_AUTH_TOKEN = apiKey;
96
+
97
+ const success = this.save(settings);
98
+
99
+ if (success) {
100
+ console.log(`✓ Plexor routing enabled`);
101
+ console.log(` Base URL: ${apiUrl}`);
102
+ console.log(` API Key: ${apiKey.substring(0, 12)}...`);
103
+ console.log(`\n All Claude Code sessions will now route through Plexor.`);
104
+ console.log(` Changes take effect immediately (no restart needed).`);
105
+ }
106
+
107
+ return success;
108
+ } catch (err) {
109
+ console.error('Failed to enable Plexor routing:', err.message);
110
+ return false;
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Disable Plexor routing by removing env vars from settings.json
116
+ *
117
+ * This restores direct connection to Anthropic API.
118
+ *
119
+ * @returns {boolean} success status
120
+ */
121
+ disablePlexorRouting() {
122
+ try {
123
+ const settings = this.load();
124
+
125
+ if (!settings.env) {
126
+ console.log('Plexor routing is not currently enabled.');
127
+ return true;
128
+ }
129
+
130
+ // Remove Plexor-specific env vars
131
+ delete settings.env.ANTHROPIC_BASE_URL;
132
+ delete settings.env.ANTHROPIC_AUTH_TOKEN;
133
+
134
+ // Clean up empty env block
135
+ if (Object.keys(settings.env).length === 0) {
136
+ delete settings.env;
137
+ }
138
+
139
+ const success = this.save(settings);
140
+
141
+ if (success) {
142
+ console.log('✓ Plexor routing disabled');
143
+ console.log(' Claude Code will now connect directly to Anthropic.');
144
+ console.log(' Changes take effect immediately (no restart needed).');
145
+ }
146
+
147
+ return success;
148
+ } catch (err) {
149
+ console.error('Failed to disable Plexor routing:', err.message);
150
+ return false;
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Get current routing status
156
+ * @returns {Object} { enabled: boolean, baseUrl: string|null, hasToken: boolean }
157
+ */
158
+ getRoutingStatus() {
159
+ try {
160
+ const settings = this.load();
161
+
162
+ const baseUrl = settings.env?.ANTHROPIC_BASE_URL || null;
163
+ const hasToken = !!settings.env?.ANTHROPIC_AUTH_TOKEN;
164
+
165
+ // Check if routing to Plexor
166
+ const isPlexorRouting = baseUrl && (
167
+ baseUrl.includes('plexor') ||
168
+ baseUrl.includes('staging.api')
169
+ );
170
+
171
+ return {
172
+ enabled: isPlexorRouting,
173
+ baseUrl,
174
+ hasToken,
175
+ isStaging: baseUrl?.includes('staging') || false,
176
+ tokenPreview: hasToken ? settings.env.ANTHROPIC_AUTH_TOKEN.substring(0, 12) + '...' : null
177
+ };
178
+ } catch {
179
+ return { enabled: false, baseUrl: null, hasToken: false };
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Update just the API key without changing other settings
185
+ * @param {string} apiKey - new Plexor API key
186
+ * @returns {boolean} success status
187
+ */
188
+ updateApiKey(apiKey) {
189
+ try {
190
+ const settings = this.load();
191
+
192
+ if (!settings.env) {
193
+ settings.env = {};
194
+ }
195
+
196
+ settings.env.ANTHROPIC_AUTH_TOKEN = apiKey;
197
+ return this.save(settings);
198
+ } catch (err) {
199
+ console.error('Failed to update API key:', err.message);
200
+ return false;
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Switch between staging and production
206
+ * @param {boolean} useStaging - true for staging, false for production
207
+ * @returns {boolean} success status
208
+ */
209
+ setEnvironment(useStaging) {
210
+ try {
211
+ const settings = this.load();
212
+
213
+ if (!settings.env?.ANTHROPIC_BASE_URL) {
214
+ console.log('Plexor routing is not enabled. Run /plexor-login first.');
215
+ return false;
216
+ }
217
+
218
+ settings.env.ANTHROPIC_BASE_URL = useStaging ? PLEXOR_STAGING_URL : PLEXOR_PROD_URL;
219
+
220
+ const success = this.save(settings);
221
+ if (success) {
222
+ console.log(`✓ Switched to ${useStaging ? 'staging' : 'production'} environment`);
223
+ }
224
+ return success;
225
+ } catch (err) {
226
+ console.error('Failed to switch environment:', err.message);
227
+ return false;
228
+ }
229
+ }
230
+ }
231
+
232
+ // Export singleton instance and class
233
+ const settingsManager = new ClaudeSettingsManager();
234
+
235
+ module.exports = {
236
+ ClaudeSettingsManager,
237
+ settingsManager,
238
+ CLAUDE_DIR,
239
+ SETTINGS_PATH,
240
+ PLEXOR_STAGING_URL,
241
+ PLEXOR_PROD_URL
242
+ };
package/package.json CHANGED
@@ -1,8 +1,14 @@
1
1
  {
2
2
  "name": "@plexor-dev/claude-code-plugin",
3
- "version": "0.1.0-beta.3",
3
+ "version": "0.1.0-beta.30",
4
4
  "description": "LLM cost optimization plugin for Claude Code - Save up to 90% on AI costs",
5
5
  "main": "lib/constants.js",
6
+ "bin": {
7
+ "plexor-status": "./commands/plexor-status.js",
8
+ "plexor-enabled": "./commands/plexor-enabled.js",
9
+ "plexor-login": "./commands/plexor-login.js",
10
+ "plexor-logout": "./commands/plexor-logout.js"
11
+ },
6
12
  "scripts": {
7
13
  "postinstall": "node scripts/postinstall.js",
8
14
  "preuninstall": "node scripts/uninstall.js",
@@ -10,6 +16,7 @@
10
16
  },
11
17
  "files": [
12
18
  "commands/",
19
+ "hooks/",
13
20
  "scripts/",
14
21
  "lib/",
15
22
  "README.md",
@@ -0,0 +1,48 @@
1
+ #!/bin/bash
2
+ # Plexor CLI - Claude Code with intelligent optimization
3
+ # This wrapper auto-enables hypervisor mode for direct gateway routing
4
+
5
+ # Colors
6
+ CYAN='\033[0;36m'
7
+ GREEN='\033[0;32m'
8
+ YELLOW='\033[0;33m'
9
+ DIM='\033[2m'
10
+ NC='\033[0m' # No Color
11
+
12
+ CONFIG_FILE="$HOME/.plexor/config.json"
13
+
14
+ # Auto-configure ANTHROPIC_BASE_URL if Plexor is enabled
15
+ if [ -f "$CONFIG_FILE" ]; then
16
+ ENABLED=$(python3 -c "import json; c=json.load(open('$CONFIG_FILE')); print(c.get('settings',{}).get('enabled', False))" 2>/dev/null)
17
+ API_URL=$(python3 -c "import json; c=json.load(open('$CONFIG_FILE')); print(c.get('settings',{}).get('apiUrl', ''))" 2>/dev/null)
18
+ API_KEY=$(python3 -c "import json; c=json.load(open('$CONFIG_FILE')); print(c.get('auth',{}).get('api_key', ''))" 2>/dev/null)
19
+ MODE=$(python3 -c "import json; c=json.load(open('$CONFIG_FILE')); print(c.get('settings',{}).get('mode', 'balanced'))" 2>/dev/null)
20
+
21
+ if [ "$ENABLED" = "True" ] && [ -n "$API_URL" ] && [ -n "$API_KEY" ]; then
22
+ # Set ANTHROPIC_BASE_URL to Plexor gateway (hypervisor mode)
23
+ export ANTHROPIC_BASE_URL="${API_URL}/gateway/anthropic/v1"
24
+ export ANTHROPIC_API_KEY="$API_KEY"
25
+
26
+ # Show Plexor branding
27
+ echo -e "${CYAN}"
28
+ cat << 'EOF'
29
+ ____ __
30
+ / __ \/ /__ _ ______ _____
31
+ / /_/ / / _ \| |/_/ __ \/ ___/
32
+ / ____/ / __/> </ /_/ / /
33
+ /_/ /_/\___/_/|_|\____/_/
34
+
35
+ EOF
36
+ echo -e "${NC}"
37
+ echo -e "${GREEN}●${NC} Hypervisor Mode: ${GREEN}Active${NC}"
38
+ echo -e " Gateway: ${DIM}${ANTHROPIC_BASE_URL}${NC}"
39
+ echo -e " Mode: ${MODE}"
40
+ echo ""
41
+ else
42
+ echo -e "${YELLOW}○${NC} Plexor: ${DIM}Disabled${NC} (run /plexor-login to enable)"
43
+ echo ""
44
+ fi
45
+ fi
46
+
47
+ # Launch claude with all arguments passed through
48
+ exec claude "$@"
@@ -10,24 +10,118 @@
10
10
  const fs = require('fs');
11
11
  const path = require('path');
12
12
  const os = require('os');
13
+ const { execSync } = require('child_process');
13
14
 
15
+ /**
16
+ * Get the correct home directory, accounting for sudo.
17
+ * When running with sudo, os.homedir() returns /root, but we want
18
+ * the actual user's home directory.
19
+ */
20
+ function getHomeDir() {
21
+ // Check if running with sudo - SUDO_USER contains the original username
22
+ if (process.env.SUDO_USER) {
23
+ // On Linux/Mac, home directories are typically /home/<user> or /Users/<user>
24
+ const platform = os.platform();
25
+ if (platform === 'darwin') {
26
+ return path.join('/Users', process.env.SUDO_USER);
27
+ } else if (platform === 'linux') {
28
+ return path.join('/home', process.env.SUDO_USER);
29
+ }
30
+ }
31
+ return os.homedir();
32
+ }
33
+
34
+ /**
35
+ * Get uid/gid for the target user (handles sudo case).
36
+ * Returns null if not running with sudo or on Windows.
37
+ */
38
+ function getTargetUserIds() {
39
+ const sudoUser = process.env.SUDO_USER;
40
+ if (!sudoUser || os.platform() === 'win32') {
41
+ return null;
42
+ }
43
+
44
+ try {
45
+ // Get uid and gid for the sudo user
46
+ const uid = parseInt(execSync(`id -u ${sudoUser}`, { encoding: 'utf8' }).trim(), 10);
47
+ const gid = parseInt(execSync(`id -g ${sudoUser}`, { encoding: 'utf8' }).trim(), 10);
48
+ return { uid, gid, user: sudoUser };
49
+ } catch {
50
+ return null;
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Recursively chown a directory and all its contents.
56
+ */
57
+ function chownRecursive(dirPath, uid, gid) {
58
+ if (!fs.existsSync(dirPath)) return;
59
+
60
+ const stat = fs.statSync(dirPath);
61
+ fs.chownSync(dirPath, uid, gid);
62
+
63
+ if (stat.isDirectory()) {
64
+ const entries = fs.readdirSync(dirPath);
65
+ for (const entry of entries) {
66
+ chownRecursive(path.join(dirPath, entry), uid, gid);
67
+ }
68
+ }
69
+ }
70
+
71
+ const HOME_DIR = getHomeDir();
14
72
  const COMMANDS_SOURCE = path.join(__dirname, '..', 'commands');
15
- const CLAUDE_COMMANDS_DIR = path.join(os.homedir(), '.claude', 'commands');
16
- const PLEXOR_CONFIG_DIR = path.join(os.homedir(), '.plexor');
73
+ const CLAUDE_COMMANDS_DIR = path.join(HOME_DIR, '.claude', 'commands');
74
+ const PLEXOR_PLUGINS_DIR = path.join(HOME_DIR, '.claude', 'plugins', 'plexor', 'commands');
75
+ const PLEXOR_CONFIG_DIR = path.join(HOME_DIR, '.plexor');
76
+ const PLEXOR_CONFIG_FILE = path.join(PLEXOR_CONFIG_DIR, 'config.json');
77
+
78
+ // Default configuration for new installs
79
+ const DEFAULT_CONFIG = {
80
+ version: 1,
81
+ auth: {
82
+ mode: "pending",
83
+ authenticated_at: null
84
+ },
85
+ settings: {
86
+ enabled: true,
87
+ apiUrl: "https://api.plexor.dev",
88
+ mode: "balanced",
89
+ localCacheEnabled: true
90
+ }
91
+ };
17
92
 
18
93
  function main() {
19
94
  try {
95
+ // Get target user info for chown (if running with sudo)
96
+ const targetUser = getTargetUserIds();
97
+
20
98
  // Create ~/.claude/commands/ if not exists
21
99
  fs.mkdirSync(CLAUDE_COMMANDS_DIR, { recursive: true });
22
100
 
101
+ // Create ~/.claude/plugins/plexor/commands/ for JS executors
102
+ fs.mkdirSync(PLEXOR_PLUGINS_DIR, { recursive: true });
103
+
23
104
  // Create ~/.plexor/ with secure permissions (owner only)
24
105
  fs.mkdirSync(PLEXOR_CONFIG_DIR, { recursive: true, mode: 0o700 });
25
106
 
26
- // Get list of command files
27
- const files = fs.readdirSync(COMMANDS_SOURCE)
107
+ // Create default config.json if it doesn't exist
108
+ let configCreated = false;
109
+ if (!fs.existsSync(PLEXOR_CONFIG_FILE)) {
110
+ fs.writeFileSync(
111
+ PLEXOR_CONFIG_FILE,
112
+ JSON.stringify(DEFAULT_CONFIG, null, 2),
113
+ { mode: 0o600 }
114
+ );
115
+ configCreated = true;
116
+ }
117
+
118
+ // Get list of command files (.md for Claude, .js for executors)
119
+ const mdFiles = fs.readdirSync(COMMANDS_SOURCE)
28
120
  .filter(f => f.endsWith('.md'));
121
+ const jsFiles = fs.readdirSync(COMMANDS_SOURCE)
122
+ .filter(f => f.endsWith('.js'));
29
123
 
30
- if (files.length === 0) {
124
+ if (mdFiles.length === 0) {
31
125
  console.error('No command files found in package. Installation may be corrupt.');
32
126
  process.exit(1);
33
127
  }
@@ -35,7 +129,8 @@ function main() {
35
129
  const installed = [];
36
130
  const backed_up = [];
37
131
 
38
- for (const file of files) {
132
+ // Copy .md command files to ~/.claude/commands/
133
+ for (const file of mdFiles) {
39
134
  const src = path.join(COMMANDS_SOURCE, file);
40
135
  const dest = path.join(CLAUDE_COMMANDS_DIR, file);
41
136
 
@@ -55,34 +150,88 @@ function main() {
55
150
  installed.push(file.replace('.md', ''));
56
151
  }
57
152
 
58
- // Print success message
153
+ // Copy .js executor files to ~/.claude/plugins/plexor/commands/
154
+ const jsInstalled = [];
155
+ for (const file of jsFiles) {
156
+ const src = path.join(COMMANDS_SOURCE, file);
157
+ const dest = path.join(PLEXOR_PLUGINS_DIR, file);
158
+ fs.copyFileSync(src, dest);
159
+ // Make executable
160
+ fs.chmodSync(dest, 0o755);
161
+ jsInstalled.push(file);
162
+ }
163
+
164
+ // Fix file ownership when running with sudo
165
+ // Files are created as root but should be owned by the original user
166
+ if (targetUser) {
167
+ const { uid, gid } = targetUser;
168
+ // Chown the .claude directory and all contents we created
169
+ chownRecursive(path.join(HOME_DIR, '.claude'), uid, gid);
170
+ // Chown the .plexor directory and all contents
171
+ chownRecursive(PLEXOR_CONFIG_DIR, uid, gid);
172
+ }
173
+
174
+ // Detect shell type
175
+ const shell = process.env.SHELL || '';
176
+ const isZsh = shell.includes('zsh');
177
+ const shellRc = isZsh ? '~/.zshrc' : '~/.bashrc';
178
+
179
+ // Print success message with clear onboarding steps
59
180
  console.log('');
60
- console.log(' ╔═══════════════════════════════════════════════════════════╗');
61
- console.log(' ║ ║');
62
- console.log(' ║ Plexor Claude Code Plugin installed successfully! ║');
63
- console.log(' ║ ║');
64
- console.log(' ╚═══════════════════════════════════════════════════════════╝');
181
+ console.log(' ╔═══════════════════════════════════════════════════════════════════╗');
182
+ console.log(' ║ ║');
183
+ console.log(' ║ Plexor Claude Code Plugin installed successfully! ║');
184
+ console.log(' ║ ║');
185
+ console.log(' ╚═══════════════════════════════════════════════════════════════════╝');
65
186
  console.log('');
66
- console.log(' Commands installed to ~/.claude/commands/:');
67
- installed.forEach(cmd => {
68
- console.log(` /${cmd}`);
69
- });
70
187
 
71
- if (backed_up.length > 0) {
72
- console.log('');
73
- console.log(' Existing files backed up (.backup):');
74
- backed_up.forEach(f => console.log(` ${f}`));
188
+ if (configCreated) {
189
+ console.log(' ✓ Created ~/.plexor/config.json');
190
+ }
191
+ console.log(` ✓ Installed ${installed.length} slash commands to ~/.claude/commands/`);
192
+ if (jsInstalled.length > 0) {
193
+ console.log(` ✓ Installed ${jsInstalled.length} executors to ~/.claude/plugins/plexor/`);
75
194
  }
195
+ if (targetUser) {
196
+ console.log(` ✓ Set file ownership to ${targetUser.user}`);
197
+ }
198
+ console.log('');
76
199
 
200
+ // CRITICAL: Make the required step VERY obvious
201
+ console.log(' ┌─────────────────────────────────────────────────────────────────┐');
202
+ console.log(' │ REQUIRED: Run this command to enable Plexor routing: │');
203
+ console.log(' └─────────────────────────────────────────────────────────────────┘');
204
+ console.log('');
205
+ console.log(' For Claude MAX users (OAuth):');
206
+ console.log('');
207
+ console.log(` echo 'export ANTHROPIC_BASE_URL="https://api.plexor.dev/gateway/anthropic"' >> ${shellRc}`);
208
+ console.log(` source ${shellRc}`);
209
+ console.log('');
210
+ console.log(' For API key users (get key at https://plexor.dev/dashboard):');
211
+ console.log('');
212
+ console.log(` echo 'export ANTHROPIC_BASE_URL="https://api.plexor.dev/gateway/anthropic"' >> ${shellRc}`);
213
+ console.log(` echo 'export ANTHROPIC_API_KEY="plx_your_key_here"' >> ${shellRc}`);
214
+ console.log(` source ${shellRc}`);
77
215
  console.log('');
78
- console.log(' Next steps:');
79
- console.log(' 1. Open Claude Code');
80
- console.log(' 2. Run /plexor-login to authenticate');
81
- console.log(' 3. Start saving on LLM costs!');
216
+ console.log(' ┌─────────────────────────────────────────────────────────────────┐');
217
+ console.log(' │ Then start Claude Code and run: /plexor-status │');
218
+ console.log(' └─────────────────────────────────────────────────────────────────┘');
219
+ console.log('');
220
+ console.log(' Available commands:');
221
+ console.log(' /plexor-setup - First-time setup wizard');
222
+ console.log(' /plexor-login - Authenticate with API key');
223
+ console.log(' /plexor-status - Check connection and see savings');
224
+ console.log(' /plexor-enabled - Enable/disable Plexor routing');
82
225
  console.log('');
83
226
  console.log(' Documentation: https://plexor.dev/docs');
84
227
  console.log('');
85
228
 
229
+ if (backed_up.length > 0) {
230
+ console.log(' Note: Existing files backed up (.backup):');
231
+ backed_up.forEach(f => console.log(` ${f}`));
232
+ console.log('');
233
+ }
234
+
86
235
  } catch (error) {
87
236
  console.error('');
88
237
  console.error(' Plexor plugin installation failed');
@@ -1,42 +0,0 @@
1
- ---
2
- description: Configure Plexor settings (user)
3
- ---
4
-
5
- # Plexor Config
6
-
7
- View and modify Plexor configuration. This is an alias for /plexor-settings.
8
-
9
- ## Steps
10
-
11
- **Step 1: Read current configuration**
12
-
13
- Use the Read tool to read `~/.plexor/config.json`.
14
-
15
- If the file doesn't exist, show:
16
- ```
17
- Plexor Config
18
- =============
19
- No configuration found. Run /plexor-login to set up Plexor.
20
- ```
21
-
22
- **Step 2: Display current configuration**
23
-
24
- ```
25
- Plexor Config
26
- =============
27
- Enabled: [enabled]
28
- API URL: [apiUrl]
29
- API Key: [show "configured" if apiKey exists, otherwise "not configured"]
30
- Mode: [mode]
31
- Provider: [preferredProvider]
32
- Local Cache: [localCacheEnabled]
33
- Timeout: [timeout]ms
34
-
35
- Configuration file: ~/.plexor/config.json
36
-
37
- Other commands:
38
- - /plexor-settings - View/edit all settings
39
- - /plexor-mode - Change optimization mode
40
- - /plexor-provider - Change provider
41
- - /plexor-enabled - Enable/disable proxy
42
- ```
@@ -1,47 +0,0 @@
1
- ---
2
- description: Set Plexor optimization mode (eco/balanced/quality/passthrough) (user)
3
- ---
4
-
5
- # Plexor Mode
6
-
7
- Set the Plexor optimization mode to control cost vs quality trade-offs.
8
-
9
- ## Steps
10
-
11
- **Step 1: Read current configuration**
12
-
13
- Use the Read tool to read `~/.plexor/config.json` and check the current `mode` setting.
14
-
15
- **Step 2: Ask user which mode they want**
16
-
17
- Use the `AskUserQuestion` tool:
18
-
19
- Question: "Which optimization mode would you like to use?"
20
- Header: "Mode"
21
- Options:
22
- 1. **eco** - Maximum savings (~$0.04/1M tokens) - Uses Ministral 3B
23
- 2. **balanced** - Good balance (~$0.15/1M) - DeepSeek, Gemini Flash, Mistral Small
24
- 3. **quality** - Premium models (~$5/1M) - Claude Opus, Gemini Pro, Mistral Large
25
- 4. **passthrough** - No optimization - Direct to requested model
26
-
27
- **Step 3: Update the configuration**
28
-
29
- Use the Read tool to get the current config, then use the Write tool to update `~/.plexor/config.json`:
30
- - Set the `mode` field to the selected value: "eco", "balanced", "quality", or "passthrough"
31
-
32
- Keep all other settings unchanged.
33
-
34
- **Step 4: Show confirmation**
35
-
36
- ```
37
- Plexor Mode: [SELECTED MODE]
38
-
39
- Mode Details:
40
- - eco: Maximum cost savings using Ministral 3B ($0.04/$0.04 per 1M tokens)
41
- - balanced: Cost-first with quality fallbacks (DeepSeek → Gemini Flash → Mistral)
42
- - quality: Premium models for complex tasks (Claude Opus, Gemini Pro)
43
- - passthrough: No optimization, direct to Anthropic
44
-
45
- Current mode: [mode]
46
- Run /plexor-status to see your savings.
47
- ```
@@ -1,47 +0,0 @@
1
- ---
2
- description: Force a specific LLM provider (claude/openai/deepseek/mistral/gemini/auto) (user)
3
- ---
4
-
5
- # Plexor Provider
6
-
7
- Set your preferred LLM provider for Plexor routing.
8
-
9
- ## Steps
10
-
11
- **Step 1: Read current configuration**
12
-
13
- Use the Read tool to read `~/.plexor/config.json` and check the current `preferredProvider` setting.
14
-
15
- **Step 2: Ask user which provider they prefer**
16
-
17
- Use the `AskUserQuestion` tool:
18
-
19
- Question: "Which LLM provider would you prefer?"
20
- Header: "Provider"
21
- Options:
22
- 1. **auto** - Let Plexor choose the best provider based on task (Recommended)
23
- 2. **deepseek** - Use DeepSeek models (cheapest, good for code)
24
- 3. **mistral** - Use Mistral models (fast, good balance)
25
- 4. **gemini** - Use Google Gemini models (good for analysis)
26
-
27
- **Step 3: Update the configuration**
28
-
29
- Use the Read tool to get the current config, then use the Write tool to update `~/.plexor/config.json`:
30
- - Set `preferredProvider` to: "auto", "deepseek", "mistral", or "gemini"
31
-
32
- Keep all other settings unchanged.
33
-
34
- **Step 4: Show confirmation**
35
-
36
- ```
37
- Plexor Provider: [SELECTED PROVIDER]
38
-
39
- Provider options:
40
- - auto: Plexor automatically selects the best provider for each task
41
- - deepseek: DeepSeek models ($0.14/$0.28 per 1M tokens) - Great for code
42
- - mistral: Mistral models ($0.10/$0.30 per 1M tokens) - Fast and versatile
43
- - gemini: Google Gemini ($0.075/$0.30 per 1M tokens) - Good for analysis
44
-
45
- Current provider: [preferredProvider]
46
- Run /plexor-status to see your usage.
47
- ```