@plexor-dev/claude-code-plugin-staging 0.1.0-beta.1 → 0.1.0-beta.10

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
@@ -32,14 +32,11 @@ This installs slash commands to `~/.claude/commands/`.
32
32
 
33
33
  | Command | Description |
34
34
  |---------|-------------|
35
- | `/plexor-login` | Authenticate with Plexor |
36
- | `/plexor-status` | View usage stats and savings |
37
- | `/plexor-mode` | Set optimization mode (eco/balanced/quality/passthrough) |
38
- | `/plexor-provider` | Force specific provider (auto/claude/deepseek/mistral/gemini) |
39
- | `/plexor-config` | Quick config (enable/disable/cache/reset) |
40
- | `/plexor-settings` | Advanced settings (API URL, mode, provider) |
41
- | `/plexor-enabled` | Enable/disable the proxy |
35
+ | `/plexor-setup` | First-time setup wizard |
36
+ | `/plexor-login` | Authenticate with Plexor API key |
42
37
  | `/plexor-logout` | Sign out and clear credentials |
38
+ | `/plexor-status` | View usage stats and savings |
39
+ | `/plexor-enabled` | Enable/disable Plexor routing |
43
40
 
44
41
  ## How It Works
45
42
 
@@ -14,26 +14,84 @@
14
14
  const fs = require('fs');
15
15
  const path = require('path');
16
16
 
17
- // Import settings manager for automatic Claude Code configuration
18
- const { settingsManager, PLEXOR_STAGING_URL, PLEXOR_PROD_URL } = require('../lib/settings-manager');
19
-
20
- const CONFIG_PATH = path.join(process.env.HOME, '.plexor', 'config.json');
21
- const PLEXOR_DIR = path.join(process.env.HOME, '.plexor');
17
+ // Import centralized constants with HOME directory validation
18
+ const { PLEXOR_DIR, CONFIG_PATH } = require('../lib/constants');
19
+
20
+ // Import settings manager with error handling for missing lib
21
+ let settingsManager, PLEXOR_STAGING_URL, PLEXOR_PROD_URL;
22
+ try {
23
+ const lib = require('../lib/settings-manager');
24
+ settingsManager = lib.settingsManager;
25
+ PLEXOR_STAGING_URL = lib.PLEXOR_STAGING_URL;
26
+ PLEXOR_PROD_URL = lib.PLEXOR_PROD_URL;
27
+ } catch (err) {
28
+ if (err.code === 'MODULE_NOT_FOUND') {
29
+ console.error('Error: Plexor plugin files are missing or corrupted.');
30
+ console.error(' Please reinstall: npm install @plexor-dev/claude-code-plugin-staging');
31
+ process.exit(1);
32
+ }
33
+ throw err;
34
+ }
22
35
 
23
36
  function loadConfig() {
24
37
  try {
38
+ if (!fs.existsSync(CONFIG_PATH)) {
39
+ return { version: 1, auth: {}, settings: {} };
40
+ }
25
41
  const data = fs.readFileSync(CONFIG_PATH, 'utf8');
26
- return JSON.parse(data);
27
- } catch {
42
+ if (!data || data.trim() === '') {
43
+ return { version: 1, auth: {}, settings: {} };
44
+ }
45
+ const config = JSON.parse(data);
46
+ if (typeof config !== 'object' || config === null) {
47
+ console.warn('Warning: Config file has invalid format, using defaults');
48
+ return { version: 1, auth: {}, settings: {} };
49
+ }
50
+ return config;
51
+ } catch (err) {
52
+ if (err instanceof SyntaxError) {
53
+ console.warn('Warning: Config file is corrupted, using defaults');
54
+ // Backup corrupted file
55
+ try {
56
+ fs.copyFileSync(CONFIG_PATH, CONFIG_PATH + '.corrupted');
57
+ } catch { /* ignore */ }
58
+ }
28
59
  return { version: 1, auth: {}, settings: {} };
29
60
  }
30
61
  }
31
62
 
32
63
  function saveConfig(config) {
33
- if (!fs.existsSync(PLEXOR_DIR)) {
34
- fs.mkdirSync(PLEXOR_DIR, { recursive: true, mode: 0o700 });
64
+ try {
65
+ if (!fs.existsSync(PLEXOR_DIR)) {
66
+ fs.mkdirSync(PLEXOR_DIR, { recursive: true, mode: 0o700 });
67
+ }
68
+
69
+ // Atomic write: write to temp file, then rename
70
+ const crypto = require('crypto');
71
+ const tempId = crypto.randomBytes(8).toString('hex');
72
+ const tempPath = path.join(PLEXOR_DIR, `.config.${tempId}.tmp`);
73
+
74
+ fs.writeFileSync(tempPath, JSON.stringify(config, null, 2), { mode: 0o600 });
75
+ fs.renameSync(tempPath, CONFIG_PATH);
76
+ return true;
77
+ } catch (err) {
78
+ if (err.code === 'EACCES' || err.code === 'EPERM') {
79
+ console.error(`Error: Cannot write to ~/.plexor/config.json`);
80
+ console.error(' Check file permissions or run with appropriate access.');
81
+ } else {
82
+ console.error('Failed to save config:', err.message);
83
+ }
84
+ return false;
35
85
  }
36
- fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });
86
+ }
87
+
88
+ /**
89
+ * Validate API key format
90
+ * @param {string} key - API key to validate
91
+ * @returns {boolean} true if valid format
92
+ */
93
+ function isValidApiKeyFormat(key) {
94
+ return key && typeof key === 'string' && key.startsWith('plx_') && key.length >= 20;
37
95
  }
38
96
 
39
97
  function main() {
@@ -80,28 +138,69 @@ function main() {
80
138
  process.exit(1);
81
139
  }
82
140
 
83
- // Update Plexor plugin config
84
- config.settings = config.settings || {};
85
- config.settings.enabled = newEnabled;
86
- saveConfig(config);
87
-
88
141
  // THE KEY FEATURE: Update Claude Code settings.json routing
89
142
  let routingUpdated = false;
143
+ let missingApiKey = false;
144
+ let invalidApiKey = false;
145
+
90
146
  if (newEnabled) {
91
- // Enable routing - need API key from config
92
- if (apiKey) {
147
+ // Enable routing - need valid API key from config
148
+ if (!apiKey) {
149
+ missingApiKey = true;
150
+ } else if (!isValidApiKeyFormat(apiKey)) {
151
+ invalidApiKey = true;
152
+ } else {
153
+ // Update Plexor plugin config first
154
+ config.settings = config.settings || {};
155
+ config.settings.enabled = newEnabled;
156
+ if (!saveConfig(config)) {
157
+ process.exit(1);
158
+ }
159
+
93
160
  // STAGING PACKAGE - uses staging API
94
161
  const apiUrl = config.settings?.apiUrl || 'https://staging.api.plexor.dev';
95
162
  const useStaging = apiUrl.includes('staging');
96
163
  routingUpdated = settingsManager.enablePlexorRouting(apiKey, { useStaging });
97
- } else {
98
- console.log('⚠ No API key found. Run /plexor-login first.');
99
164
  }
100
165
  } else {
166
+ // Update Plexor plugin config
167
+ config.settings = config.settings || {};
168
+ config.settings.enabled = newEnabled;
169
+ if (!saveConfig(config)) {
170
+ process.exit(1);
171
+ }
172
+
101
173
  // Disable routing - remove env vars from settings.json
102
174
  routingUpdated = settingsManager.disablePlexorRouting();
103
175
  }
104
176
 
177
+ // Show error if no API key when enabling
178
+ if (missingApiKey) {
179
+ console.log(`┌─────────────────────────────────────────────┐`);
180
+ console.log(`│ ✗ Cannot Enable Plexor │`);
181
+ console.log(`├─────────────────────────────────────────────┤`);
182
+ console.log(`│ No API key configured. │`);
183
+ console.log(`│ Run /plexor-login <api-key> first. │`);
184
+ console.log(`├─────────────────────────────────────────────┤`);
185
+ console.log(`│ Get your API key at: │`);
186
+ console.log(`│ https://plexor.dev/dashboard/api-keys │`);
187
+ console.log(`└─────────────────────────────────────────────┘`);
188
+ process.exit(1);
189
+ }
190
+
191
+ // Show error if API key format is invalid
192
+ if (invalidApiKey) {
193
+ console.log(`┌─────────────────────────────────────────────┐`);
194
+ console.log(`│ ✗ Cannot Enable Plexor │`);
195
+ console.log(`├─────────────────────────────────────────────┤`);
196
+ console.log(`│ Invalid API key format in config. │`);
197
+ console.log(`│ Keys must start with "plx_" (20+ chars). │`);
198
+ console.log(`├─────────────────────────────────────────────┤`);
199
+ console.log(`│ Run /plexor-login <api-key> to fix. │`);
200
+ console.log(`└─────────────────────────────────────────────┘`);
201
+ process.exit(1);
202
+ }
203
+
105
204
  const newStatus = newEnabled ? '● Enabled' : '○ Disabled';
106
205
  const prevStatus = currentEnabled ? 'Enabled' : 'Disabled';
107
206
  const routingMsg = routingUpdated
@@ -4,25 +4,45 @@ description: Enable or disable Plexor proxy (routes all traffic through Plexor A
4
4
 
5
5
  # Plexor Enabled
6
6
 
7
- Run this command to view or toggle the Plexor proxy:
7
+ Toggle Plexor proxy on or off.
8
+
9
+ ## If argument provided (on/off/true/false)
10
+
11
+ Run the command directly with the argument:
8
12
 
9
13
  ```bash
10
- node ~/.claude/plugins/plexor/commands/plexor-enabled.js
14
+ node ~/.claude/plugins/plexor/commands/plexor-enabled.js <argument>
11
15
  ```
12
16
 
13
- To enable or disable, pass an argument:
17
+ Then display the output and STOP.
18
+
19
+ ## If NO argument provided
20
+
21
+ **Step 1**: First get current status by running:
14
22
 
15
23
  ```bash
16
- node ~/.claude/plugins/plexor/commands/plexor-enabled.js true
17
- node ~/.claude/plugins/plexor/commands/plexor-enabled.js false
24
+ node ~/.claude/plugins/plexor/commands/plexor-enabled.js
18
25
  ```
19
26
 
20
- Use the Bash tool to execute this command.
27
+ **Step 2**: Based on the output, use AskUserQuestion to present options:
28
+
29
+ If currently ENABLED (shows "● Enabled" or "● Active"):
30
+ - Question: "Plexor is currently ON. What would you like to do?"
31
+ - Header: "Plexor"
32
+ - Options:
33
+ 1. **Turn OFF** - Disable Plexor routing (connect directly to Anthropic)
34
+ 2. **Keep ON** - No change
35
+
36
+ If currently DISABLED (shows "○ Disabled" or "○ Inactive"):
37
+ - Question: "Plexor is currently OFF. What would you like to do?"
38
+ - Header: "Plexor"
39
+ - Options:
40
+ 1. **Turn ON** - Enable Plexor routing
41
+ 2. **Keep OFF** - No change
21
42
 
22
- **IMPORTANT**: After running this command and displaying the output, STOP. Do not:
23
- - Read any files
24
- - Explore the codebase
25
- - Run additional commands
26
- - Ask follow-up questions
43
+ **Step 3**: Based on user selection:
44
+ - If "Turn OFF" selected: Run `node ~/.claude/plugins/plexor/commands/plexor-enabled.js false`
45
+ - If "Turn ON" selected: Run `node ~/.claude/plugins/plexor/commands/plexor-enabled.js true`
46
+ - If "Keep" selected: Do nothing, just confirm current state
27
47
 
28
- The command output is the complete response. Simply show the output and wait for the user's next input.
48
+ **IMPORTANT**: After completing, STOP. Do not read files, explore codebase, or run additional commands.
@@ -13,28 +13,67 @@ const path = require('path');
13
13
  const https = require('https');
14
14
  const http = require('http');
15
15
 
16
- // Import settings manager for automatic Claude Code configuration
17
- const { settingsManager } = require('../lib/settings-manager');
16
+ // Import centralized constants with HOME directory validation
17
+ const { PLEXOR_DIR, CONFIG_PATH, DEFAULT_API_URL } = require('../lib/constants');
18
18
 
19
- const CONFIG_PATH = path.join(process.env.HOME, '.plexor', 'config.json');
20
- const PLEXOR_DIR = path.join(process.env.HOME, '.plexor');
21
- // STAGING PACKAGE - uses staging API
22
- const DEFAULT_API_URL = 'https://staging.api.plexor.dev';
19
+ // Import settings manager with error handling for missing lib
20
+ let settingsManager;
21
+ try {
22
+ settingsManager = require('../lib/settings-manager').settingsManager;
23
+ } catch (err) {
24
+ if (err.code === 'MODULE_NOT_FOUND') {
25
+ console.error('Error: Plexor plugin files are missing or corrupted.');
26
+ console.error(' Please reinstall: npm install @plexor-dev/claude-code-plugin-staging');
27
+ process.exit(1);
28
+ }
29
+ throw err;
30
+ }
23
31
 
24
32
  function loadConfig() {
25
33
  try {
34
+ if (!fs.existsSync(CONFIG_PATH)) {
35
+ return { version: 1, auth: {}, settings: {} };
36
+ }
26
37
  const data = fs.readFileSync(CONFIG_PATH, 'utf8');
27
- return JSON.parse(data);
28
- } catch {
38
+ if (!data || data.trim() === '') {
39
+ return { version: 1, auth: {}, settings: {} };
40
+ }
41
+ const config = JSON.parse(data);
42
+ if (typeof config !== 'object' || config === null) {
43
+ return { version: 1, auth: {}, settings: {} };
44
+ }
45
+ return config;
46
+ } catch (err) {
47
+ if (err instanceof SyntaxError) {
48
+ console.warn('Warning: Config file is corrupted, will be overwritten');
49
+ }
29
50
  return { version: 1, auth: {}, settings: {} };
30
51
  }
31
52
  }
32
53
 
33
54
  function saveConfig(config) {
34
- if (!fs.existsSync(PLEXOR_DIR)) {
35
- fs.mkdirSync(PLEXOR_DIR, { recursive: true, mode: 0o700 });
55
+ try {
56
+ if (!fs.existsSync(PLEXOR_DIR)) {
57
+ fs.mkdirSync(PLEXOR_DIR, { recursive: true, mode: 0o700 });
58
+ }
59
+
60
+ // Atomic write: write to temp file, then rename
61
+ const crypto = require('crypto');
62
+ const tempId = crypto.randomBytes(8).toString('hex');
63
+ const tempPath = path.join(PLEXOR_DIR, `.config.${tempId}.tmp`);
64
+
65
+ fs.writeFileSync(tempPath, JSON.stringify(config, null, 2), { mode: 0o600 });
66
+ fs.renameSync(tempPath, CONFIG_PATH);
67
+ return true;
68
+ } catch (err) {
69
+ if (err.code === 'EACCES' || err.code === 'EPERM') {
70
+ console.error('Error: Cannot write to ~/.plexor/config.json');
71
+ console.error(' Check file permissions or run with appropriate access.');
72
+ } else {
73
+ console.error('Failed to save config:', err.message);
74
+ }
75
+ return false;
36
76
  }
37
- fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });
38
77
  }
39
78
 
40
79
  function validateApiKey(apiUrl, apiKey) {
@@ -80,23 +119,62 @@ function validateApiKey(apiUrl, apiKey) {
80
119
  });
81
120
  }
82
121
 
83
- async function promptForApiKey() {
84
- const rl = readline.createInterface({
85
- input: process.stdin,
86
- output: process.stdout
87
- });
122
+ /**
123
+ * Read API key from stdin (for piped input)
124
+ * @returns {Promise<string>} The API key read from stdin
125
+ */
126
+ function readFromStdin() {
127
+ return new Promise((resolve, reject) => {
128
+ let data = '';
129
+ const timeout = setTimeout(() => {
130
+ reject(new Error('Timeout reading from stdin'));
131
+ }, 5000);
88
132
 
89
- return new Promise((resolve) => {
90
- rl.question('Enter your Plexor API key: ', (answer) => {
91
- rl.close();
92
- resolve(answer.trim());
133
+ process.stdin.setEncoding('utf8');
134
+ process.stdin.on('data', (chunk) => {
135
+ data += chunk;
136
+ });
137
+ process.stdin.on('end', () => {
138
+ clearTimeout(timeout);
139
+ resolve(data.trim());
140
+ });
141
+ process.stdin.on('error', (err) => {
142
+ clearTimeout(timeout);
143
+ reject(err);
93
144
  });
145
+ process.stdin.resume();
94
146
  });
95
147
  }
96
148
 
97
149
  async function main() {
98
150
  const args = process.argv.slice(2);
99
- let apiKey = args[0];
151
+ let apiKey = null;
152
+ let keySource = null;
153
+
154
+ // SECURITY FIX: Check for API key in order of preference
155
+ // 1. Environment variable (most secure for scripts/CI)
156
+ // 2. Stdin pipe (secure for interactive use)
157
+ // 3. Command line argument (warns about security risk)
158
+
159
+ // Check environment variable first (most secure)
160
+ if (process.env.PLEXOR_API_KEY) {
161
+ apiKey = process.env.PLEXOR_API_KEY;
162
+ keySource = 'environment';
163
+ }
164
+ // Check if stdin has data (piped input)
165
+ else if (!process.stdin.isTTY && args.length === 0) {
166
+ try {
167
+ apiKey = await readFromStdin();
168
+ keySource = 'stdin';
169
+ } catch {
170
+ // Stdin read failed, continue to check args
171
+ }
172
+ }
173
+ // Check command line argument (least secure - shows in ps)
174
+ else if (args[0]) {
175
+ apiKey = args[0];
176
+ keySource = 'argument';
177
+ }
100
178
 
101
179
  // Check for existing login
102
180
  const config = loadConfig();
@@ -108,14 +186,14 @@ async function main() {
108
186
  console.log(`├─────────────────────────────────────────────┤`);
109
187
  console.log(`│ API Key: ${(existingKey.substring(0, 8) + '...').padEnd(33)}│`);
110
188
  console.log(`│ To re-login, provide a new key: │`);
111
- console.log(`│ /plexor-login <api-key> │`);
189
+ console.log(`│ echo $PLEXOR_API_KEY | /plexor-login │`);
112
190
  console.log(`│ To logout: │`);
113
191
  console.log(`│ /plexor-logout │`);
114
192
  console.log(`└─────────────────────────────────────────────┘`);
115
193
  return;
116
194
  }
117
195
 
118
- // If no key provided, prompt for it
196
+ // If no key provided, show secure usage options
119
197
  if (!apiKey) {
120
198
  console.log(`┌─────────────────────────────────────────────┐`);
121
199
  console.log(`│ Plexor Login │`);
@@ -123,11 +201,25 @@ async function main() {
123
201
  console.log(`│ Get your API key at: │`);
124
202
  console.log(`│ https://plexor.dev/dashboard/api-keys │`);
125
203
  console.log(`├─────────────────────────────────────────────┤`);
126
- console.log(`│ Usage: /plexor-login <api-key> │`);
204
+ console.log(`│ Secure usage (recommended): │`);
205
+ console.log(`│ echo "plx_..." | /plexor-login │`);
206
+ console.log(`│ PLEXOR_API_KEY=plx_... /plexor-login │`);
207
+ console.log(`├─────────────────────────────────────────────┤`);
208
+ console.log(`│ Direct usage (visible in ps): │`);
209
+ console.log(`│ /plexor-login <api-key> │`);
127
210
  console.log(`└─────────────────────────────────────────────┘`);
128
211
  return;
129
212
  }
130
213
 
214
+ // Warn if API key was passed as command line argument
215
+ if (keySource === 'argument') {
216
+ console.log(`⚠ Security note: API key passed as argument is visible in`);
217
+ console.log(` process list (ps aux). For better security, use:`);
218
+ console.log(` echo "plx_..." | /plexor-login`);
219
+ console.log(` PLEXOR_API_KEY=plx_... /plexor-login`);
220
+ console.log('');
221
+ }
222
+
131
223
  // Validate key format
132
224
  if (!apiKey.startsWith('plx_') || apiKey.length < 20) {
133
225
  console.error(`Error: Invalid API key format`);
@@ -146,7 +238,9 @@ async function main() {
146
238
  config.auth.api_key = apiKey;
147
239
  config.settings = config.settings || {};
148
240
  config.settings.enabled = true;
149
- saveConfig(config);
241
+ if (!saveConfig(config)) {
242
+ process.exit(1);
243
+ }
150
244
 
151
245
  // AUTO-CONFIGURE CLAUDE CODE ROUTING
152
246
  // This is the key feature: automatically set ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN
@@ -8,25 +8,68 @@
8
8
  const fs = require('fs');
9
9
  const path = require('path');
10
10
 
11
- const PLEXOR_DIR = path.join(process.env.HOME, '.plexor');
12
- const CONFIG_PATH = path.join(PLEXOR_DIR, 'config.json');
13
- const SESSION_PATH = path.join(PLEXOR_DIR, 'session.json');
14
- const CACHE_PATH = path.join(PLEXOR_DIR, 'cache.json');
11
+ // Import centralized constants with HOME directory validation
12
+ const { PLEXOR_DIR, CONFIG_PATH, SESSION_PATH, CACHE_PATH } = require('../lib/constants');
13
+
14
+ // Import settings manager for Claude Code routing cleanup
15
+ let settingsManager;
16
+ try {
17
+ const lib = require('../lib/settings-manager');
18
+ settingsManager = lib.settingsManager;
19
+ } catch (err) {
20
+ if (err.code === 'MODULE_NOT_FOUND') {
21
+ console.error('Error: Plexor plugin files are missing or corrupted.');
22
+ console.error(' Please reinstall: npm install @plexor-dev/claude-code-plugin-staging');
23
+ process.exit(1);
24
+ }
25
+ throw err;
26
+ }
15
27
 
16
28
  function loadConfig() {
17
29
  try {
30
+ if (!fs.existsSync(CONFIG_PATH)) {
31
+ return null;
32
+ }
18
33
  const data = fs.readFileSync(CONFIG_PATH, 'utf8');
19
- return JSON.parse(data);
20
- } catch {
34
+ if (!data || data.trim() === '') {
35
+ return null;
36
+ }
37
+ const config = JSON.parse(data);
38
+ if (typeof config !== 'object' || config === null) {
39
+ return null;
40
+ }
41
+ return config;
42
+ } catch (err) {
43
+ if (err instanceof SyntaxError) {
44
+ console.warn('Warning: Config file is corrupted');
45
+ }
21
46
  return null;
22
47
  }
23
48
  }
24
49
 
25
50
  function saveConfig(config) {
26
- if (!fs.existsSync(PLEXOR_DIR)) {
27
- fs.mkdirSync(PLEXOR_DIR, { recursive: true, mode: 0o700 });
51
+ try {
52
+ if (!fs.existsSync(PLEXOR_DIR)) {
53
+ fs.mkdirSync(PLEXOR_DIR, { recursive: true, mode: 0o700 });
54
+ }
55
+
56
+ // Atomic write: write to temp file, then rename
57
+ const crypto = require('crypto');
58
+ const tempId = crypto.randomBytes(8).toString('hex');
59
+ const tempPath = path.join(PLEXOR_DIR, `.config.${tempId}.tmp`);
60
+
61
+ fs.writeFileSync(tempPath, JSON.stringify(config, null, 2), { mode: 0o600 });
62
+ fs.renameSync(tempPath, CONFIG_PATH);
63
+ return true;
64
+ } catch (err) {
65
+ if (err.code === 'EACCES' || err.code === 'EPERM') {
66
+ console.error('Error: Cannot write to ~/.plexor/config.json');
67
+ console.error(' Check file permissions or run with appropriate access.');
68
+ } else {
69
+ console.error('Failed to save config:', err.message);
70
+ }
71
+ return false;
28
72
  }
29
- fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });
30
73
  }
31
74
 
32
75
  function deleteFile(filePath) {
@@ -61,7 +104,14 @@ function main() {
61
104
  delete config.auth.api_key;
62
105
  config.settings = config.settings || {};
63
106
  config.settings.enabled = false;
64
- saveConfig(config);
107
+ if (!saveConfig(config)) {
108
+ process.exit(1);
109
+ }
110
+
111
+ // CRITICAL FIX: Disable Claude Code routing in ~/.claude/settings.json
112
+ // This removes ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN so Claude Code
113
+ // no longer tries to route through Plexor with removed credentials
114
+ const routingDisabled = settingsManager.disablePlexorRouting();
65
115
 
66
116
  // Clear session
67
117
  deleteFile(SESSION_PATH);
@@ -76,12 +126,13 @@ function main() {
76
126
  console.log(`│ ✓ Logged Out │`);
77
127
  console.log(`├─────────────────────────────────────────────┤`);
78
128
  console.log(`│ ✓ API key removed │`);
79
- console.log(`│ ✓ Plexor proxy disabled │`);
129
+ console.log(`│ ${routingDisabled ? '' : '○'} Claude Code routing disabled │`);
80
130
  console.log(`│ ✓ Session cleared │`);
81
131
  if (clearCache) {
82
132
  console.log(`│ ${cacheCleared ? '✓' : '○'} Cache cleared │`);
83
133
  }
84
134
  console.log(`├─────────────────────────────────────────────┤`);
135
+ console.log(`│ Claude Code now connects directly. │`);
85
136
  console.log(`│ Run /plexor-login to re-authenticate. │`);
86
137
  if (!clearCache) {
87
138
  console.log(`│ Use --clear-cache to also clear cache. │`);
@@ -61,7 +61,7 @@ If user selected "Yes, I have Claude MAX":
61
61
  },
62
62
  "settings": {
63
63
  "enabled": true,
64
- "apiUrl": "https://api.plexor.dev",
64
+ "apiUrl": "https://staging.api.plexor.dev",
65
65
  "mode": "balanced",
66
66
  "localCacheEnabled": true
67
67
  }
@@ -72,7 +72,7 @@ If user selected "Yes, I have Claude MAX":
72
72
  ```json
73
73
  {
74
74
  "env": {
75
- "ANTHROPIC_BASE_URL": "https://api.plexor.dev/gateway/anthropic",
75
+ "ANTHROPIC_BASE_URL": "https://staging.api.plexor.dev/gateway/anthropic",
76
76
  "ANTHROPIC_AUTH_TOKEN": "[user's Plexor key]"
77
77
  }
78
78
  }
@@ -122,7 +122,7 @@ If user selected "No, I'll use a Plexor API key":
122
122
  },
123
123
  "settings": {
124
124
  "enabled": true,
125
- "apiUrl": "https://api.plexor.dev",
125
+ "apiUrl": "https://staging.api.plexor.dev",
126
126
  "preferred_provider": "auto",
127
127
  "mode": "balanced",
128
128
  "localCacheEnabled": true
@@ -134,7 +134,7 @@ If user selected "No, I'll use a Plexor API key":
134
134
  ```json
135
135
  {
136
136
  "env": {
137
- "ANTHROPIC_BASE_URL": "https://api.plexor.dev/gateway/anthropic",
137
+ "ANTHROPIC_BASE_URL": "https://staging.api.plexor.dev/gateway/anthropic",
138
138
  "ANTHROPIC_AUTH_TOKEN": "[user's Plexor key]"
139
139
  }
140
140
  }