@plexor-dev/claude-code-plugin 0.1.0-beta.24 → 0.1.0-beta.26
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/commands/plexor-enabled.js +42 -11
- package/commands/plexor-login.js +23 -3
- package/commands/plexor-setup.md +73 -35
- package/commands/plexor-status.js +28 -1
- package/lib/constants.js +2 -1
- package/lib/settings-manager.js +240 -0
- package/package.json +1 -1
|
@@ -3,11 +3,20 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* Plexor Enabled Command
|
|
5
5
|
* Enable or disable Plexor optimization proxy
|
|
6
|
+
*
|
|
7
|
+
* KEY FEATURE: When toggling on/off, automatically updates ~/.claude/settings.json
|
|
8
|
+
* to route or un-route ALL Claude Code sessions through Plexor gateway.
|
|
9
|
+
*
|
|
10
|
+
* THE DREAM: User just runs "/plexor-enabled off" to disable, "/plexor-enabled on" to enable.
|
|
11
|
+
* No manual environment variables or config updates required!
|
|
6
12
|
*/
|
|
7
13
|
|
|
8
14
|
const fs = require('fs');
|
|
9
15
|
const path = require('path');
|
|
10
16
|
|
|
17
|
+
// Import settings manager for automatic Claude Code configuration
|
|
18
|
+
const { settingsManager, PLEXOR_STAGING_URL, PLEXOR_PROD_URL } = require('../lib/settings-manager');
|
|
19
|
+
|
|
11
20
|
const CONFIG_PATH = path.join(process.env.HOME, '.plexor', 'config.json');
|
|
12
21
|
const PLEXOR_DIR = path.join(process.env.HOME, '.plexor');
|
|
13
22
|
|
|
@@ -31,14 +40,23 @@ function main() {
|
|
|
31
40
|
const args = process.argv.slice(2);
|
|
32
41
|
const config = loadConfig();
|
|
33
42
|
const currentEnabled = config.settings?.enabled ?? false;
|
|
43
|
+
const apiKey = config.auth?.api_key;
|
|
44
|
+
|
|
45
|
+
// Get current Claude settings.json routing status
|
|
46
|
+
const routingStatus = settingsManager.getRoutingStatus();
|
|
34
47
|
|
|
35
48
|
// No args - show current status
|
|
36
49
|
if (args.length === 0) {
|
|
37
50
|
const status = currentEnabled ? '● Enabled' : '○ Disabled';
|
|
51
|
+
const routingStr = routingStatus.enabled ? '● Active' : '○ Inactive';
|
|
38
52
|
console.log(`┌─────────────────────────────────────────────┐`);
|
|
39
53
|
console.log(`│ Plexor Proxy Status │`);
|
|
40
54
|
console.log(`├─────────────────────────────────────────────┤`);
|
|
41
|
-
console.log(`│
|
|
55
|
+
console.log(`│ Plugin Config: ${status.padEnd(27)}│`);
|
|
56
|
+
console.log(`│ Claude Routing: ${routingStr.padEnd(26)}│`);
|
|
57
|
+
if (routingStatus.enabled) {
|
|
58
|
+
console.log(`│ Endpoint: ${(routingStatus.isStaging ? 'Staging' : 'Production').padEnd(32)}│`);
|
|
59
|
+
}
|
|
42
60
|
console.log(`├─────────────────────────────────────────────┤`);
|
|
43
61
|
console.log(`│ Usage: │`);
|
|
44
62
|
console.log(`│ /plexor-enabled true - Enable proxy │`);
|
|
@@ -62,21 +80,33 @@ function main() {
|
|
|
62
80
|
process.exit(1);
|
|
63
81
|
}
|
|
64
82
|
|
|
65
|
-
|
|
66
|
-
const state = currentEnabled ? 'enabled' : 'disabled';
|
|
67
|
-
console.log(`Plexor proxy is already ${state}`);
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
83
|
+
// Update Plexor plugin config
|
|
71
84
|
config.settings = config.settings || {};
|
|
72
85
|
config.settings.enabled = newEnabled;
|
|
73
86
|
saveConfig(config);
|
|
74
87
|
|
|
88
|
+
// THE KEY FEATURE: Update Claude Code settings.json routing
|
|
89
|
+
let routingUpdated = false;
|
|
90
|
+
if (newEnabled) {
|
|
91
|
+
// Enable routing - need API key from config
|
|
92
|
+
if (apiKey) {
|
|
93
|
+
// Default to staging for now - will change to production later
|
|
94
|
+
const apiUrl = config.settings?.apiUrl || 'https://staging.api.plexor.dev';
|
|
95
|
+
const useStaging = apiUrl.includes('staging');
|
|
96
|
+
routingUpdated = settingsManager.enablePlexorRouting(apiKey, { useStaging });
|
|
97
|
+
} else {
|
|
98
|
+
console.log('⚠ No API key found. Run /plexor-login first.');
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
// Disable routing - remove env vars from settings.json
|
|
102
|
+
routingUpdated = settingsManager.disablePlexorRouting();
|
|
103
|
+
}
|
|
104
|
+
|
|
75
105
|
const newStatus = newEnabled ? '● Enabled' : '○ Disabled';
|
|
76
106
|
const prevStatus = currentEnabled ? 'Enabled' : 'Disabled';
|
|
77
|
-
const
|
|
78
|
-
? '
|
|
79
|
-
: '
|
|
107
|
+
const routingMsg = routingUpdated
|
|
108
|
+
? (newEnabled ? 'Claude Code now routes through Plexor' : 'Claude Code now connects directly')
|
|
109
|
+
: 'Manual routing update may be needed';
|
|
80
110
|
|
|
81
111
|
console.log(`┌─────────────────────────────────────────────┐`);
|
|
82
112
|
console.log(`│ ✓ Plexor Proxy Updated │`);
|
|
@@ -84,7 +114,8 @@ function main() {
|
|
|
84
114
|
console.log(`│ Previous: ${prevStatus.padEnd(32)}│`);
|
|
85
115
|
console.log(`│ New: ${newStatus.padEnd(37)}│`);
|
|
86
116
|
console.log(`├─────────────────────────────────────────────┤`);
|
|
87
|
-
console.log(`│ ${
|
|
117
|
+
console.log(`│ ${routingMsg.padEnd(42)}│`);
|
|
118
|
+
console.log(`│ Changes take effect immediately. │`);
|
|
88
119
|
console.log(`└─────────────────────────────────────────────┘`);
|
|
89
120
|
}
|
|
90
121
|
|
package/commands/plexor-login.js
CHANGED
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Plexor Login Command
|
|
5
|
-
* Authenticate with Plexor API
|
|
5
|
+
* Authenticate with Plexor API and auto-configure Claude Code routing
|
|
6
|
+
*
|
|
7
|
+
* KEY FEATURE: After successful login, automatically configures ~/.claude/settings.json
|
|
8
|
+
* to route ALL Claude Code sessions through Plexor gateway.
|
|
6
9
|
*/
|
|
7
10
|
|
|
8
11
|
const fs = require('fs');
|
|
@@ -10,9 +13,13 @@ const path = require('path');
|
|
|
10
13
|
const https = require('https');
|
|
11
14
|
const http = require('http');
|
|
12
15
|
|
|
16
|
+
// Import settings manager for automatic Claude Code configuration
|
|
17
|
+
const { settingsManager } = require('../lib/settings-manager');
|
|
18
|
+
|
|
13
19
|
const CONFIG_PATH = path.join(process.env.HOME, '.plexor', 'config.json');
|
|
14
20
|
const PLEXOR_DIR = path.join(process.env.HOME, '.plexor');
|
|
15
|
-
|
|
21
|
+
// Default to staging for now - will change to production later
|
|
22
|
+
const DEFAULT_API_URL = 'https://staging.api.plexor.dev';
|
|
16
23
|
|
|
17
24
|
function loadConfig() {
|
|
18
25
|
try {
|
|
@@ -141,6 +148,12 @@ async function main() {
|
|
|
141
148
|
config.settings.enabled = true;
|
|
142
149
|
saveConfig(config);
|
|
143
150
|
|
|
151
|
+
// AUTO-CONFIGURE CLAUDE CODE ROUTING
|
|
152
|
+
// This is the key feature: automatically set ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN
|
|
153
|
+
// in ~/.claude/settings.json so ALL Claude Code sessions route through Plexor
|
|
154
|
+
const useStaging = apiUrl.includes('staging');
|
|
155
|
+
const routingEnabled = settingsManager.enablePlexorRouting(apiKey, { useStaging });
|
|
156
|
+
|
|
144
157
|
const email = user.email || 'Unknown';
|
|
145
158
|
const tier = user.tier?.name || 'Free';
|
|
146
159
|
|
|
@@ -150,7 +163,14 @@ async function main() {
|
|
|
150
163
|
console.log(`│ Email: ${email.substring(0, 35).padEnd(35)}│`);
|
|
151
164
|
console.log(`│ Tier: ${tier.padEnd(36)}│`);
|
|
152
165
|
console.log(`├─────────────────────────────────────────────┤`);
|
|
153
|
-
|
|
166
|
+
if (routingEnabled) {
|
|
167
|
+
console.log(`│ ✓ Claude Code routing: CONFIGURED │`);
|
|
168
|
+
console.log(`│ All sessions now route through Plexor │`);
|
|
169
|
+
} else {
|
|
170
|
+
console.log(`│ ⚠ Claude Code routing: MANUAL SETUP NEEDED │`);
|
|
171
|
+
console.log(`│ Set ANTHROPIC_BASE_URL in environment │`);
|
|
172
|
+
}
|
|
173
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
154
174
|
console.log(`│ Run /plexor-status to see your stats. │`);
|
|
155
175
|
console.log(`└─────────────────────────────────────────────┘`);
|
|
156
176
|
} catch (err) {
|
package/commands/plexor-setup.md
CHANGED
|
@@ -4,13 +4,16 @@ description: First-time setup wizard for Plexor with Claude Code (user)
|
|
|
4
4
|
|
|
5
5
|
# Plexor Setup Wizard
|
|
6
6
|
|
|
7
|
-
Guide users through first-time Plexor setup
|
|
7
|
+
Guide users through first-time Plexor setup. **No manual environment variable configuration required!**
|
|
8
|
+
|
|
9
|
+
The plugin automatically configures `~/.claude/settings.json` to route all Claude Code sessions through Plexor.
|
|
8
10
|
|
|
9
11
|
## Steps
|
|
10
12
|
|
|
11
13
|
**Step 1: Check if already configured**
|
|
12
14
|
|
|
13
15
|
Use the Read tool to check if `~/.plexor/config.json` exists and has valid configuration.
|
|
16
|
+
Also check `~/.claude/settings.json` for routing status.
|
|
14
17
|
|
|
15
18
|
If configured, show:
|
|
16
19
|
```
|
|
@@ -21,30 +24,38 @@ Already configured!
|
|
|
21
24
|
API URL: [apiUrl from config]
|
|
22
25
|
Mode: [mode from config]
|
|
23
26
|
Status: [Enabled/Disabled]
|
|
27
|
+
Claude Routing: [Active/Inactive]
|
|
24
28
|
|
|
25
29
|
Run /plexor-status to see your usage.
|
|
26
30
|
Run /plexor-settings to modify configuration.
|
|
31
|
+
Run /plexor-enabled off to disable routing.
|
|
27
32
|
```
|
|
28
33
|
|
|
29
|
-
**Step 2: Ask about Claude
|
|
34
|
+
**Step 2: Ask about Claude subscription**
|
|
30
35
|
|
|
31
36
|
Use the AskUserQuestion tool:
|
|
32
37
|
|
|
33
|
-
Question: "
|
|
34
|
-
Header: "
|
|
38
|
+
Question: "How do you pay for Claude usage?"
|
|
39
|
+
Header: "Billing"
|
|
35
40
|
Options:
|
|
36
|
-
1. **
|
|
37
|
-
2. **
|
|
41
|
+
1. **Claude MAX subscription (Pro/Team/Enterprise)** - I have a subscription and want Plexor for optimization & tracking (you'll still need a Plexor API key)
|
|
42
|
+
2. **Pay-per-use via Plexor** - I want Plexor to handle billing and route to the cheapest provider
|
|
38
43
|
|
|
39
44
|
**Step 3A: Claude MAX User Setup**
|
|
40
45
|
|
|
41
46
|
If user selected "Yes, I have Claude MAX":
|
|
42
47
|
|
|
43
|
-
1.
|
|
48
|
+
1. Ask for their Plexor API key:
|
|
49
|
+
"Please provide your Plexor API key (starts with 'plx_')."
|
|
50
|
+
"Get one at: https://plexor.dev/dashboard"
|
|
51
|
+
"Your MAX subscription will be used for Claude - the Plexor key is for tracking/optimization."
|
|
52
|
+
|
|
53
|
+
2. Use the Write tool to create `~/.plexor/config.json`:
|
|
44
54
|
```json
|
|
45
55
|
{
|
|
46
56
|
"version": 1,
|
|
47
57
|
"auth": {
|
|
58
|
+
"api_key": "[user's Plexor key]",
|
|
48
59
|
"mode": "oauth_passthrough",
|
|
49
60
|
"authenticated_at": "[current ISO timestamp]"
|
|
50
61
|
},
|
|
@@ -57,24 +68,39 @@ If user selected "Yes, I have Claude MAX":
|
|
|
57
68
|
}
|
|
58
69
|
```
|
|
59
70
|
|
|
60
|
-
|
|
71
|
+
3. Use the Write tool to update `~/.claude/settings.json` env block:
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"env": {
|
|
75
|
+
"ANTHROPIC_BASE_URL": "https://api.plexor.dev/gateway/anthropic",
|
|
76
|
+
"ANTHROPIC_AUTH_TOKEN": "[user's Plexor key]"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
Note: Preserve any existing settings, just add/update the env block.
|
|
81
|
+
|
|
82
|
+
4. Show the user:
|
|
61
83
|
```
|
|
62
84
|
Plexor Setup - Claude MAX User
|
|
63
85
|
==============================
|
|
64
|
-
|
|
86
|
+
Setup Complete! No manual configuration needed.
|
|
65
87
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
Then restart your terminal or run: source ~/.bashrc
|
|
88
|
+
What was configured:
|
|
89
|
+
- ~/.plexor/config.json (Plexor plugin settings)
|
|
90
|
+
- ~/.claude/settings.json (automatic Claude Code routing)
|
|
71
91
|
|
|
72
92
|
How it works:
|
|
73
|
-
- Claude Code
|
|
74
|
-
-
|
|
93
|
+
- All Claude Code sessions now route through Plexor
|
|
94
|
+
- Your MAX subscription OAuth token is passed through
|
|
75
95
|
- You keep your MAX benefits ($0 cost, 20x rate limits)
|
|
96
|
+
- Plexor optimizes prompts and tracks usage
|
|
97
|
+
|
|
98
|
+
Commands:
|
|
99
|
+
- /plexor-status - See your usage stats
|
|
100
|
+
- /plexor-enabled off - Temporarily disable Plexor
|
|
101
|
+
- /plexor-enabled on - Re-enable Plexor
|
|
76
102
|
|
|
77
|
-
|
|
103
|
+
Changes take effect immediately in all Claude Code sessions!
|
|
78
104
|
```
|
|
79
105
|
|
|
80
106
|
**Step 3B: API Key User Setup**
|
|
@@ -104,31 +130,43 @@ If user selected "No, I'll use a Plexor API key":
|
|
|
104
130
|
}
|
|
105
131
|
```
|
|
106
132
|
|
|
107
|
-
3.
|
|
133
|
+
3. Use the Write tool to update `~/.claude/settings.json` env block:
|
|
134
|
+
```json
|
|
135
|
+
{
|
|
136
|
+
"env": {
|
|
137
|
+
"ANTHROPIC_BASE_URL": "https://api.plexor.dev/gateway/anthropic",
|
|
138
|
+
"ANTHROPIC_AUTH_TOKEN": "[user's Plexor key]"
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
Note: Preserve any existing settings, just add/update the env block.
|
|
143
|
+
|
|
144
|
+
4. Show the user:
|
|
108
145
|
```
|
|
109
146
|
Plexor Setup - API Key User
|
|
110
147
|
===========================
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
Add these lines to your shell profile (~/.bashrc or ~/.zshrc):
|
|
148
|
+
Setup Complete! No manual configuration needed.
|
|
114
149
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
Then restart your terminal or run: source ~/.bashrc
|
|
150
|
+
What was configured:
|
|
151
|
+
- ~/.plexor/config.json (Plexor plugin settings)
|
|
152
|
+
- ~/.claude/settings.json (automatic Claude Code routing)
|
|
119
153
|
|
|
120
154
|
How it works:
|
|
121
|
-
-
|
|
155
|
+
- All Claude Code sessions now route through Plexor
|
|
122
156
|
- Plexor picks the best provider (can save up to 90%)
|
|
123
|
-
- Your
|
|
157
|
+
- Your usage is tracked and optimized
|
|
124
158
|
|
|
125
|
-
|
|
126
|
-
|
|
159
|
+
Commands:
|
|
160
|
+
- /plexor-status - See your usage and savings
|
|
161
|
+
- /plexor-mode eco - Maximize savings
|
|
162
|
+
- /plexor-mode quality - Maximize quality
|
|
163
|
+
- /plexor-enabled off - Temporarily disable Plexor
|
|
127
164
|
|
|
128
|
-
|
|
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).
|
|
165
|
+
Changes take effect immediately in all Claude Code sessions!
|
|
166
|
+
```
|
|
133
167
|
|
|
134
|
-
**IMPORTANT**:
|
|
168
|
+
**IMPORTANT NOTES**:
|
|
169
|
+
- The `~/.claude/settings.json` env block is the KEY mechanism that routes Claude Code through Plexor
|
|
170
|
+
- ANTHROPIC_AUTH_TOKEN takes precedence over ANTHROPIC_API_KEY (use AUTH_TOKEN for the Plexor key)
|
|
171
|
+
- Changes take effect immediately - no shell restart needed
|
|
172
|
+
- After completing setup, STOP. Do not run additional commands.
|
|
@@ -11,8 +11,30 @@ const https = require('https');
|
|
|
11
11
|
|
|
12
12
|
const CONFIG_PATH = path.join(process.env.HOME, '.plexor', 'config.json');
|
|
13
13
|
const SESSION_PATH = path.join(process.env.HOME, '.plexor', 'session.json');
|
|
14
|
+
const CLAUDE_SETTINGS_PATH = path.join(process.env.HOME, '.claude', 'settings.json');
|
|
14
15
|
const SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
|
|
15
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Check if Claude Code is actually routing through Plexor
|
|
19
|
+
* by reading ~/.claude/settings.json
|
|
20
|
+
*/
|
|
21
|
+
function getRoutingStatus() {
|
|
22
|
+
try {
|
|
23
|
+
const data = fs.readFileSync(CLAUDE_SETTINGS_PATH, 'utf8');
|
|
24
|
+
const settings = JSON.parse(data);
|
|
25
|
+
const baseUrl = settings.env?.ANTHROPIC_BASE_URL || '';
|
|
26
|
+
const hasToken = !!settings.env?.ANTHROPIC_AUTH_TOKEN;
|
|
27
|
+
const isPlexorRouting = baseUrl.includes('plexor') || baseUrl.includes('staging.api');
|
|
28
|
+
return {
|
|
29
|
+
active: isPlexorRouting && hasToken,
|
|
30
|
+
baseUrl,
|
|
31
|
+
isStaging: baseUrl.includes('staging')
|
|
32
|
+
};
|
|
33
|
+
} catch {
|
|
34
|
+
return { active: false, baseUrl: null, isStaging: false };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
16
38
|
function loadSessionStats() {
|
|
17
39
|
try {
|
|
18
40
|
const data = fs.readFileSync(SESSION_PATH, 'utf8');
|
|
@@ -138,8 +160,13 @@ ${line(`├── Tokens saved: ${sessionTokensSaved} (${sessionTokensSavedPct}%
|
|
|
138
160
|
${line(`└── Cost saved: $${sessionCostSaved}`)}
|
|
139
161
|
` : '';
|
|
140
162
|
|
|
163
|
+
// Get routing status from Claude settings.json
|
|
164
|
+
const routing = getRoutingStatus();
|
|
165
|
+
const routingIndicator = routing.active ? '🟢 PLEXOR MODE: ON' : '🔴 PLEXOR MODE: OFF';
|
|
166
|
+
const envLabel = routing.isStaging ? '(staging)' : '(production)';
|
|
167
|
+
|
|
141
168
|
console.log(` ┌─────────────────────────────────────────────┐
|
|
142
|
-
${line('
|
|
169
|
+
${line(routingIndicator + (routing.active ? ' ' + envLabel : ''))}
|
|
143
170
|
├─────────────────────────────────────────────┤
|
|
144
171
|
${line(`Account: ${tierName}`)}
|
|
145
172
|
${line(`Email: ${email}`)}
|
package/lib/constants.js
CHANGED
|
@@ -11,7 +11,8 @@ const CACHE_PATH = path.join(PLEXOR_DIR, 'cache.json');
|
|
|
11
11
|
|
|
12
12
|
const SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
// Default to staging for now - will change to production later
|
|
15
|
+
const DEFAULT_API_URL = 'https://staging.api.plexor.dev';
|
|
15
16
|
const DEFAULT_TIMEOUT = 5000;
|
|
16
17
|
|
|
17
18
|
module.exports = {
|
|
@@ -0,0 +1,240 @@
|
|
|
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
|
+
// Return empty object if file doesn't exist or parse error
|
|
42
|
+
return {};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Save Claude settings
|
|
48
|
+
* @param {Object} settings - settings object to save
|
|
49
|
+
* @returns {boolean} success status
|
|
50
|
+
*/
|
|
51
|
+
save(settings) {
|
|
52
|
+
try {
|
|
53
|
+
// Ensure .claude directory exists
|
|
54
|
+
if (!fs.existsSync(this.claudeDir)) {
|
|
55
|
+
fs.mkdirSync(this.claudeDir, { recursive: true });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
fs.writeFileSync(this.settingsPath, JSON.stringify(settings, null, 2));
|
|
59
|
+
return true;
|
|
60
|
+
} catch (err) {
|
|
61
|
+
console.error('Failed to save Claude settings:', err.message);
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Enable Plexor routing by setting env vars in settings.json
|
|
68
|
+
*
|
|
69
|
+
* This is the KEY mechanism: setting ANTHROPIC_BASE_URL and ANTHROPIC_AUTH_TOKEN
|
|
70
|
+
* in the env block redirects ALL Claude Code sessions to Plexor automatically.
|
|
71
|
+
*
|
|
72
|
+
* @param {string} apiKey - Plexor API key (plx_*)
|
|
73
|
+
* @param {Object} options - { useStaging: boolean }
|
|
74
|
+
* @returns {boolean} success status
|
|
75
|
+
*/
|
|
76
|
+
enablePlexorRouting(apiKey, options = {}) {
|
|
77
|
+
// Default to staging for now - will change to production later
|
|
78
|
+
// TODO: Auto-detect staging keys (plx_protodemo_*, plx_staging_*) vs production
|
|
79
|
+
const { useStaging = true } = options;
|
|
80
|
+
const apiUrl = useStaging ? PLEXOR_STAGING_URL : PLEXOR_PROD_URL;
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
const settings = this.load();
|
|
84
|
+
|
|
85
|
+
// Initialize env block if doesn't exist
|
|
86
|
+
if (!settings.env) {
|
|
87
|
+
settings.env = {};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Set the magic environment variables
|
|
91
|
+
// ANTHROPIC_AUTH_TOKEN has higher precedence than ANTHROPIC_API_KEY
|
|
92
|
+
settings.env.ANTHROPIC_BASE_URL = apiUrl;
|
|
93
|
+
settings.env.ANTHROPIC_AUTH_TOKEN = apiKey;
|
|
94
|
+
|
|
95
|
+
const success = this.save(settings);
|
|
96
|
+
|
|
97
|
+
if (success) {
|
|
98
|
+
console.log(`✓ Plexor routing enabled`);
|
|
99
|
+
console.log(` Base URL: ${apiUrl}`);
|
|
100
|
+
console.log(` API Key: ${apiKey.substring(0, 12)}...`);
|
|
101
|
+
console.log(`\n All Claude Code sessions will now route through Plexor.`);
|
|
102
|
+
console.log(` Changes take effect immediately (no restart needed).`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return success;
|
|
106
|
+
} catch (err) {
|
|
107
|
+
console.error('Failed to enable Plexor routing:', err.message);
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Disable Plexor routing by removing env vars from settings.json
|
|
114
|
+
*
|
|
115
|
+
* This restores direct connection to Anthropic API.
|
|
116
|
+
*
|
|
117
|
+
* @returns {boolean} success status
|
|
118
|
+
*/
|
|
119
|
+
disablePlexorRouting() {
|
|
120
|
+
try {
|
|
121
|
+
const settings = this.load();
|
|
122
|
+
|
|
123
|
+
if (!settings.env) {
|
|
124
|
+
console.log('Plexor routing is not currently enabled.');
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Remove Plexor-specific env vars
|
|
129
|
+
delete settings.env.ANTHROPIC_BASE_URL;
|
|
130
|
+
delete settings.env.ANTHROPIC_AUTH_TOKEN;
|
|
131
|
+
|
|
132
|
+
// Clean up empty env block
|
|
133
|
+
if (Object.keys(settings.env).length === 0) {
|
|
134
|
+
delete settings.env;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const success = this.save(settings);
|
|
138
|
+
|
|
139
|
+
if (success) {
|
|
140
|
+
console.log('✓ Plexor routing disabled');
|
|
141
|
+
console.log(' Claude Code will now connect directly to Anthropic.');
|
|
142
|
+
console.log(' Changes take effect immediately (no restart needed).');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return success;
|
|
146
|
+
} catch (err) {
|
|
147
|
+
console.error('Failed to disable Plexor routing:', err.message);
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Get current routing status
|
|
154
|
+
* @returns {Object} { enabled: boolean, baseUrl: string|null, hasToken: boolean }
|
|
155
|
+
*/
|
|
156
|
+
getRoutingStatus() {
|
|
157
|
+
try {
|
|
158
|
+
const settings = this.load();
|
|
159
|
+
|
|
160
|
+
const baseUrl = settings.env?.ANTHROPIC_BASE_URL || null;
|
|
161
|
+
const hasToken = !!settings.env?.ANTHROPIC_AUTH_TOKEN;
|
|
162
|
+
|
|
163
|
+
// Check if routing to Plexor
|
|
164
|
+
const isPlexorRouting = baseUrl && (
|
|
165
|
+
baseUrl.includes('plexor') ||
|
|
166
|
+
baseUrl.includes('staging.api')
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
enabled: isPlexorRouting,
|
|
171
|
+
baseUrl,
|
|
172
|
+
hasToken,
|
|
173
|
+
isStaging: baseUrl?.includes('staging') || false,
|
|
174
|
+
tokenPreview: hasToken ? settings.env.ANTHROPIC_AUTH_TOKEN.substring(0, 12) + '...' : null
|
|
175
|
+
};
|
|
176
|
+
} catch {
|
|
177
|
+
return { enabled: false, baseUrl: null, hasToken: false };
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Update just the API key without changing other settings
|
|
183
|
+
* @param {string} apiKey - new Plexor API key
|
|
184
|
+
* @returns {boolean} success status
|
|
185
|
+
*/
|
|
186
|
+
updateApiKey(apiKey) {
|
|
187
|
+
try {
|
|
188
|
+
const settings = this.load();
|
|
189
|
+
|
|
190
|
+
if (!settings.env) {
|
|
191
|
+
settings.env = {};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
settings.env.ANTHROPIC_AUTH_TOKEN = apiKey;
|
|
195
|
+
return this.save(settings);
|
|
196
|
+
} catch (err) {
|
|
197
|
+
console.error('Failed to update API key:', err.message);
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Switch between staging and production
|
|
204
|
+
* @param {boolean} useStaging - true for staging, false for production
|
|
205
|
+
* @returns {boolean} success status
|
|
206
|
+
*/
|
|
207
|
+
setEnvironment(useStaging) {
|
|
208
|
+
try {
|
|
209
|
+
const settings = this.load();
|
|
210
|
+
|
|
211
|
+
if (!settings.env?.ANTHROPIC_BASE_URL) {
|
|
212
|
+
console.log('Plexor routing is not enabled. Run /plexor-login first.');
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
settings.env.ANTHROPIC_BASE_URL = useStaging ? PLEXOR_STAGING_URL : PLEXOR_PROD_URL;
|
|
217
|
+
|
|
218
|
+
const success = this.save(settings);
|
|
219
|
+
if (success) {
|
|
220
|
+
console.log(`✓ Switched to ${useStaging ? 'staging' : 'production'} environment`);
|
|
221
|
+
}
|
|
222
|
+
return success;
|
|
223
|
+
} catch (err) {
|
|
224
|
+
console.error('Failed to switch environment:', err.message);
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Export singleton instance and class
|
|
231
|
+
const settingsManager = new ClaudeSettingsManager();
|
|
232
|
+
|
|
233
|
+
module.exports = {
|
|
234
|
+
ClaudeSettingsManager,
|
|
235
|
+
settingsManager,
|
|
236
|
+
CLAUDE_DIR,
|
|
237
|
+
SETTINGS_PATH,
|
|
238
|
+
PLEXOR_STAGING_URL,
|
|
239
|
+
PLEXOR_PROD_URL
|
|
240
|
+
};
|
package/package.json
CHANGED