@plexor-dev/claude-code-plugin-staging 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.
- package/README.md +4 -7
- package/commands/plexor-agent.js +84 -0
- package/commands/plexor-agent.md +36 -0
- package/commands/plexor-enabled.js +177 -18
- package/commands/plexor-enabled.md +31 -13
- package/commands/plexor-login.js +211 -42
- package/commands/plexor-login.md +4 -21
- package/commands/plexor-logout.js +72 -14
- package/commands/plexor-logout.md +2 -20
- package/commands/plexor-provider.js +62 -81
- package/commands/plexor-provider.md +23 -13
- package/commands/plexor-routing.js +77 -0
- package/commands/plexor-routing.md +37 -0
- package/commands/plexor-settings.js +161 -123
- package/commands/plexor-settings.md +38 -14
- package/commands/plexor-setup.js +253 -0
- package/commands/plexor-setup.md +16 -160
- package/commands/plexor-status.js +244 -18
- package/commands/plexor-status.md +1 -13
- package/commands/plexor-uninstall.js +319 -0
- package/commands/plexor-uninstall.md +12 -0
- package/hooks/intercept.js +211 -32
- package/hooks/track-response.js +302 -2
- package/lib/config-utils.js +314 -0
- package/lib/config.js +22 -3
- package/lib/constants.js +19 -1
- package/lib/logger.js +64 -5
- package/lib/settings-manager.js +233 -24
- package/lib/verify-route.js +77 -0
- package/package.json +6 -4
- package/scripts/postinstall.js +271 -44
- package/scripts/uninstall.js +194 -41
- package/commands/plexor-config.js +0 -170
- package/commands/plexor-config.md +0 -28
- package/commands/plexor-mode.js +0 -107
- package/commands/plexor-mode.md +0 -27
package/commands/plexor-login.js
CHANGED
|
@@ -13,28 +13,79 @@ const path = require('path');
|
|
|
13
13
|
const https = require('https');
|
|
14
14
|
const http = require('http');
|
|
15
15
|
|
|
16
|
-
// Import
|
|
17
|
-
const {
|
|
16
|
+
// Import centralized constants with HOME directory validation
|
|
17
|
+
const { PLEXOR_DIR, CONFIG_PATH, DEFAULT_API_URL } = require('../lib/constants');
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
28
|
-
|
|
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
|
-
|
|
35
|
-
fs.
|
|
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;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function isPlexorApiKey(token) {
|
|
80
|
+
return typeof token === 'string' && token.startsWith('plx_') && token.length >= 20;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function isJwtToken(token) {
|
|
84
|
+
if (typeof token !== 'string' || !token.startsWith('eyJ')) {
|
|
85
|
+
return false;
|
|
36
86
|
}
|
|
37
|
-
|
|
87
|
+
const parts = token.split('.');
|
|
88
|
+
return parts.length === 3 && parts.every(part => part.length > 0);
|
|
38
89
|
}
|
|
39
90
|
|
|
40
91
|
function validateApiKey(apiUrl, apiKey) {
|
|
@@ -80,23 +131,112 @@ function validateApiKey(apiUrl, apiKey) {
|
|
|
80
131
|
});
|
|
81
132
|
}
|
|
82
133
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
134
|
+
function validateJwtToken(apiUrl, jwtToken) {
|
|
135
|
+
return new Promise((resolve, reject) => {
|
|
136
|
+
const url = new URL(`${apiUrl}/v1/auth/me`);
|
|
137
|
+
const isHttps = url.protocol === 'https:';
|
|
138
|
+
const lib = isHttps ? https : http;
|
|
139
|
+
|
|
140
|
+
const options = {
|
|
141
|
+
hostname: url.hostname,
|
|
142
|
+
port: url.port || (isHttps ? 443 : 80),
|
|
143
|
+
path: url.pathname,
|
|
144
|
+
method: 'GET',
|
|
145
|
+
headers: {
|
|
146
|
+
'Authorization': `Bearer ${jwtToken}`
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const req = lib.request(options, (res) => {
|
|
151
|
+
let data = '';
|
|
152
|
+
res.on('data', chunk => data += chunk);
|
|
153
|
+
res.on('end', () => {
|
|
154
|
+
if (res.statusCode === 200) {
|
|
155
|
+
try {
|
|
156
|
+
resolve(JSON.parse(data));
|
|
157
|
+
} catch {
|
|
158
|
+
reject(new Error('Invalid response from server'));
|
|
159
|
+
}
|
|
160
|
+
} else if (res.statusCode === 401) {
|
|
161
|
+
reject(new Error('Invalid login token'));
|
|
162
|
+
} else {
|
|
163
|
+
reject(new Error(`Server error: ${res.statusCode}`));
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
req.on('error', (err) => reject(new Error(`Connection failed: ${err.message}`)));
|
|
169
|
+
req.setTimeout(10000, () => {
|
|
170
|
+
req.destroy();
|
|
171
|
+
reject(new Error('Connection timeout'));
|
|
172
|
+
});
|
|
173
|
+
req.end();
|
|
87
174
|
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function validateCredential(apiUrl, credential) {
|
|
178
|
+
if (isJwtToken(credential)) {
|
|
179
|
+
return validateJwtToken(apiUrl, credential);
|
|
180
|
+
}
|
|
181
|
+
return validateApiKey(apiUrl, credential);
|
|
182
|
+
}
|
|
88
183
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
184
|
+
/**
|
|
185
|
+
* Read API key from stdin (for piped input)
|
|
186
|
+
* @returns {Promise<string>} The API key read from stdin
|
|
187
|
+
*/
|
|
188
|
+
function readFromStdin() {
|
|
189
|
+
return new Promise((resolve, reject) => {
|
|
190
|
+
let data = '';
|
|
191
|
+
const timeout = setTimeout(() => {
|
|
192
|
+
reject(new Error('Timeout reading from stdin'));
|
|
193
|
+
}, 5000);
|
|
194
|
+
|
|
195
|
+
process.stdin.setEncoding('utf8');
|
|
196
|
+
process.stdin.on('data', (chunk) => {
|
|
197
|
+
data += chunk;
|
|
198
|
+
});
|
|
199
|
+
process.stdin.on('end', () => {
|
|
200
|
+
clearTimeout(timeout);
|
|
201
|
+
resolve(data.trim());
|
|
202
|
+
});
|
|
203
|
+
process.stdin.on('error', (err) => {
|
|
204
|
+
clearTimeout(timeout);
|
|
205
|
+
reject(err);
|
|
93
206
|
});
|
|
207
|
+
process.stdin.resume();
|
|
94
208
|
});
|
|
95
209
|
}
|
|
96
210
|
|
|
97
211
|
async function main() {
|
|
98
212
|
const args = process.argv.slice(2);
|
|
99
|
-
let apiKey =
|
|
213
|
+
let apiKey = null;
|
|
214
|
+
let keySource = null;
|
|
215
|
+
|
|
216
|
+
// SECURITY FIX: Check for API key in order of preference
|
|
217
|
+
// 1. Environment variable (most secure for scripts/CI)
|
|
218
|
+
// 2. Stdin pipe (secure for interactive use)
|
|
219
|
+
// 3. Command line argument (warns about security risk)
|
|
220
|
+
|
|
221
|
+
// Check environment variable first (most secure)
|
|
222
|
+
if (process.env.PLEXOR_API_KEY) {
|
|
223
|
+
apiKey = process.env.PLEXOR_API_KEY;
|
|
224
|
+
keySource = 'environment';
|
|
225
|
+
}
|
|
226
|
+
// Check if stdin has data (piped input)
|
|
227
|
+
else if (!process.stdin.isTTY && args.length === 0) {
|
|
228
|
+
try {
|
|
229
|
+
apiKey = await readFromStdin();
|
|
230
|
+
keySource = 'stdin';
|
|
231
|
+
} catch {
|
|
232
|
+
// Stdin read failed, continue to check args
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// Check command line argument (least secure - shows in ps)
|
|
236
|
+
else if (args[0]) {
|
|
237
|
+
apiKey = args[0];
|
|
238
|
+
keySource = 'argument';
|
|
239
|
+
}
|
|
100
240
|
|
|
101
241
|
// Check for existing login
|
|
102
242
|
const config = loadConfig();
|
|
@@ -107,31 +247,46 @@ async function main() {
|
|
|
107
247
|
console.log(`│ Already Logged In │`);
|
|
108
248
|
console.log(`├─────────────────────────────────────────────┤`);
|
|
109
249
|
console.log(`│ API Key: ${(existingKey.substring(0, 8) + '...').padEnd(33)}│`);
|
|
110
|
-
console.log(`│
|
|
111
|
-
console.log(`│
|
|
112
|
-
console.log(`│ To logout:
|
|
113
|
-
console.log(`│ /plexor-logout │`);
|
|
250
|
+
console.log(`│ Human setup path: /plexor-setup │`);
|
|
251
|
+
console.log(`│ Automation path: /plexor-login <key> │`);
|
|
252
|
+
console.log(`│ To logout: /plexor-logout │`);
|
|
114
253
|
console.log(`└─────────────────────────────────────────────┘`);
|
|
115
254
|
return;
|
|
116
255
|
}
|
|
117
256
|
|
|
118
|
-
// If no key provided,
|
|
257
|
+
// If no key provided, show secure usage options
|
|
119
258
|
if (!apiKey) {
|
|
120
259
|
console.log(`┌─────────────────────────────────────────────┐`);
|
|
121
|
-
console.log(`│ Plexor Login
|
|
260
|
+
console.log(`│ Plexor Login (Advanced) │`);
|
|
261
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
262
|
+
console.log(`│ Human first-run: /plexor-setup │`);
|
|
122
263
|
console.log(`├─────────────────────────────────────────────┤`);
|
|
123
264
|
console.log(`│ Get your API key at: │`);
|
|
124
265
|
console.log(`│ https://plexor.dev/dashboard/api-keys │`);
|
|
125
266
|
console.log(`├─────────────────────────────────────────────┤`);
|
|
126
|
-
console.log(`│
|
|
267
|
+
console.log(`│ Secure usage (recommended): │`);
|
|
268
|
+
console.log(`│ echo "plx_..." | /plexor-login │`);
|
|
269
|
+
console.log(`│ PLEXOR_API_KEY=plx_... /plexor-login │`);
|
|
270
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
271
|
+
console.log(`│ Direct usage (visible in ps): │`);
|
|
272
|
+
console.log(`│ /plexor-login <api-key> │`);
|
|
127
273
|
console.log(`└─────────────────────────────────────────────┘`);
|
|
128
274
|
return;
|
|
129
275
|
}
|
|
130
276
|
|
|
131
|
-
//
|
|
132
|
-
if (
|
|
133
|
-
console.
|
|
134
|
-
console.
|
|
277
|
+
// Warn if API key was passed as command line argument
|
|
278
|
+
if (keySource === 'argument') {
|
|
279
|
+
console.log(`⚠ Security note: API key passed as argument is visible in`);
|
|
280
|
+
console.log(` process list (ps aux). For better security, use:`);
|
|
281
|
+
console.log(` echo "plx_..." | /plexor-login`);
|
|
282
|
+
console.log(` PLEXOR_API_KEY=plx_... /plexor-login`);
|
|
283
|
+
console.log('');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Validate credential format (Plexor API key OR login JWT)
|
|
287
|
+
if (!isPlexorApiKey(apiKey) && !isJwtToken(apiKey)) {
|
|
288
|
+
console.error(`Error: Invalid credential format`);
|
|
289
|
+
console.error(`Expected Plexor API key ("plx_...") or login token ("eyJ...")`);
|
|
135
290
|
process.exit(1);
|
|
136
291
|
}
|
|
137
292
|
|
|
@@ -140,38 +295,52 @@ async function main() {
|
|
|
140
295
|
console.log('Validating API key...');
|
|
141
296
|
|
|
142
297
|
try {
|
|
143
|
-
const user = await
|
|
298
|
+
const user = await validateCredential(apiUrl, apiKey);
|
|
144
299
|
|
|
145
300
|
config.auth = config.auth || {};
|
|
146
301
|
config.auth.api_key = apiKey;
|
|
147
302
|
config.settings = config.settings || {};
|
|
148
303
|
config.settings.enabled = true;
|
|
149
|
-
saveConfig(config)
|
|
304
|
+
if (!saveConfig(config)) {
|
|
305
|
+
process.exit(1);
|
|
306
|
+
}
|
|
150
307
|
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
// in ~/.claude/settings.json so ALL Claude Code sessions route through Plexor
|
|
308
|
+
// Automation path: save credentials and activate routing.
|
|
309
|
+
// Guided human setup should go through /plexor-setup, which also verifies the route.
|
|
154
310
|
const useStaging = apiUrl.includes('staging');
|
|
155
311
|
const routingEnabled = settingsManager.enablePlexorRouting(apiKey, { useStaging });
|
|
156
312
|
|
|
313
|
+
config.health = {
|
|
314
|
+
installed: true,
|
|
315
|
+
connected: true,
|
|
316
|
+
routing_active: routingEnabled,
|
|
317
|
+
verified: false,
|
|
318
|
+
verified_at: null,
|
|
319
|
+
verify_error: 'Verification not run. Use /plexor-setup for guided verification.',
|
|
320
|
+
gateway: useStaging ? 'staging' : 'production',
|
|
321
|
+
previous_auth_preserved: false
|
|
322
|
+
};
|
|
323
|
+
saveConfig(config);
|
|
324
|
+
|
|
157
325
|
const email = user.email || 'Unknown';
|
|
158
326
|
const tier = user.tier?.name || 'Free';
|
|
159
327
|
|
|
160
328
|
console.log(`┌─────────────────────────────────────────────┐`);
|
|
161
|
-
console.log(`│ ✓
|
|
329
|
+
console.log(`│ ✓ Plexor Credentials Saved │`);
|
|
162
330
|
console.log(`├─────────────────────────────────────────────┤`);
|
|
163
331
|
console.log(`│ Email: ${email.substring(0, 35).padEnd(35)}│`);
|
|
164
332
|
console.log(`│ Tier: ${tier.padEnd(36)}│`);
|
|
165
333
|
console.log(`├─────────────────────────────────────────────┤`);
|
|
166
334
|
if (routingEnabled) {
|
|
167
|
-
console.log(`│ ✓ Claude
|
|
168
|
-
console.log(`│
|
|
335
|
+
console.log(`│ ✓ Claude routing: ACTIVE │`);
|
|
336
|
+
console.log(`│ ○ Claude verify: NOT RUN │`);
|
|
169
337
|
} else {
|
|
170
|
-
console.log(`│ ⚠ Claude
|
|
171
|
-
console.log(`│
|
|
338
|
+
console.log(`│ ⚠ Claude routing: MANUAL SETUP NEEDED │`);
|
|
339
|
+
console.log(`│ Run /plexor-setup after fixing permissions │`);
|
|
172
340
|
}
|
|
173
341
|
console.log(`├─────────────────────────────────────────────┤`);
|
|
174
|
-
console.log(`│
|
|
342
|
+
console.log(`│ Human first-run: /plexor-setup │`);
|
|
343
|
+
console.log(`│ Automation complete. Status: /plexor-status│`);
|
|
175
344
|
console.log(`└─────────────────────────────────────────────┘`);
|
|
176
345
|
} catch (err) {
|
|
177
346
|
console.error(`┌─────────────────────────────────────────────┐`);
|
package/commands/plexor-login.md
CHANGED
|
@@ -1,27 +1,10 @@
|
|
|
1
|
+
description: Advanced/manual Plexor authentication for automation and repair (user)
|
|
1
2
|
---
|
|
2
|
-
description: Authenticate with Plexor to enable optimization (user)
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Plexor Login
|
|
6
3
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
node ~/.claude/plugins/plexor/commands/plexor-login.js
|
|
11
|
-
```
|
|
4
|
+
**RULE: Execute the bash command below EXACTLY ONCE. After the Bash tool returns output, your ONLY action is to present that output to the user. DO NOT re-execute the command. DO NOT call any other tools.**
|
|
12
5
|
|
|
13
|
-
|
|
6
|
+
Pass the API key as argument (format: `plx_your_api_key_here`).
|
|
14
7
|
|
|
15
8
|
```bash
|
|
16
|
-
node ~/.claude/plugins/plexor/commands/plexor-login.js
|
|
9
|
+
node ~/.claude/plugins/plexor/commands/plexor-login.js $ARGUMENTS
|
|
17
10
|
```
|
|
18
|
-
|
|
19
|
-
Use the Bash tool to execute this command.
|
|
20
|
-
|
|
21
|
-
**IMPORTANT**: After running this command and displaying the output, STOP. Do not:
|
|
22
|
-
- Read any files
|
|
23
|
-
- Explore the codebase
|
|
24
|
-
- Run additional commands
|
|
25
|
-
- Ask follow-up questions
|
|
26
|
-
|
|
27
|
-
The command output is the complete response. Simply show the output and wait for the user's next input.
|
|
@@ -8,25 +8,68 @@
|
|
|
8
8
|
const fs = require('fs');
|
|
9
9
|
const path = require('path');
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
const CONFIG_PATH =
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
20
|
-
|
|
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
|
-
|
|
27
|
-
fs.
|
|
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) {
|
|
@@ -47,21 +90,34 @@ function main() {
|
|
|
47
90
|
|
|
48
91
|
if (!config || !config.auth?.api_key) {
|
|
49
92
|
console.log(`┌─────────────────────────────────────────────┐`);
|
|
50
|
-
console.log(`│ Not
|
|
93
|
+
console.log(`│ Plexor Is Not Active │`);
|
|
51
94
|
console.log(`├─────────────────────────────────────────────┤`);
|
|
52
95
|
console.log(`│ No active Plexor session found. │`);
|
|
53
|
-
console.log(`│ Run /plexor-
|
|
96
|
+
console.log(`│ Run /plexor-setup to connect Plexor. │`);
|
|
54
97
|
console.log(`└─────────────────────────────────────────────┘`);
|
|
55
98
|
return;
|
|
56
99
|
}
|
|
57
100
|
|
|
58
101
|
const clearCache = args.includes('--clear-cache') || args.includes('-c');
|
|
102
|
+
const currentSettings = settingsManager.load();
|
|
103
|
+
const hadPriorAuth = Boolean(
|
|
104
|
+
currentSettings.env?.PLEXOR_PREVIOUS_ANTHROPIC_API_KEY ||
|
|
105
|
+
currentSettings.env?.PLEXOR_PREVIOUS_ANTHROPIC_AUTH_TOKEN
|
|
106
|
+
);
|
|
59
107
|
|
|
60
108
|
// Clear credentials
|
|
61
109
|
delete config.auth.api_key;
|
|
62
110
|
config.settings = config.settings || {};
|
|
63
111
|
config.settings.enabled = false;
|
|
64
|
-
|
|
112
|
+
delete config.health;
|
|
113
|
+
if (!saveConfig(config)) {
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// CRITICAL FIX: Disable Claude Code routing in ~/.claude/settings.json
|
|
118
|
+
// This removes ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN so Claude Code
|
|
119
|
+
// no longer tries to route through Plexor with removed credentials
|
|
120
|
+
const routingDisabled = settingsManager.disablePlexorRouting();
|
|
65
121
|
|
|
66
122
|
// Clear session
|
|
67
123
|
deleteFile(SESSION_PATH);
|
|
@@ -76,13 +132,15 @@ function main() {
|
|
|
76
132
|
console.log(`│ ✓ Logged Out │`);
|
|
77
133
|
console.log(`├─────────────────────────────────────────────┤`);
|
|
78
134
|
console.log(`│ ✓ API key removed │`);
|
|
79
|
-
console.log(`│ ✓
|
|
135
|
+
console.log(`│ ${routingDisabled ? '✓' : '○'} Claude Code routing disabled │`);
|
|
136
|
+
console.log(`│ ${hadPriorAuth ? '✓' : '○'} Prior Claude auth restored │`);
|
|
80
137
|
console.log(`│ ✓ Session cleared │`);
|
|
81
138
|
if (clearCache) {
|
|
82
139
|
console.log(`│ ${cacheCleared ? '✓' : '○'} Cache cleared │`);
|
|
83
140
|
}
|
|
84
141
|
console.log(`├─────────────────────────────────────────────┤`);
|
|
85
|
-
console.log(`│
|
|
142
|
+
console.log(`│ Claude Code now connects directly. │`);
|
|
143
|
+
console.log(`│ Run /plexor-setup to reconnect Plexor. │`);
|
|
86
144
|
if (!clearCache) {
|
|
87
145
|
console.log(`│ Use --clear-cache to also clear cache. │`);
|
|
88
146
|
}
|
|
@@ -2,26 +2,8 @@
|
|
|
2
2
|
description: Log out from Plexor and clear credentials (user)
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Run this command to log out and clear credentials:
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
node ~/.claude/plugins/plexor/commands/plexor-logout.js
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
To also clear the cache:
|
|
5
|
+
**RULE: Execute the bash command below EXACTLY ONCE. After the Bash tool returns output, your ONLY action is to present that output to the user. DO NOT re-execute the command. DO NOT call any other tools.**
|
|
14
6
|
|
|
15
7
|
```bash
|
|
16
|
-
node ~/.claude/plugins/plexor/commands/plexor-logout.js
|
|
8
|
+
node ~/.claude/plugins/plexor/commands/plexor-logout.js $ARGUMENTS
|
|
17
9
|
```
|
|
18
|
-
|
|
19
|
-
Use the Bash tool to execute this command.
|
|
20
|
-
|
|
21
|
-
**IMPORTANT**: After running this command and displaying the output, STOP. Do not:
|
|
22
|
-
- Read any files
|
|
23
|
-
- Explore the codebase
|
|
24
|
-
- Run additional commands
|
|
25
|
-
- Ask follow-up questions
|
|
26
|
-
|
|
27
|
-
The command output is the complete response. Simply show the output and wait for the user's next input.
|