@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
|
@@ -1,28 +1,52 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: View and change Plexor settings — routing mode, agent autonomy, LLM provider (user)
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Step 1: Check if arguments were provided.**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
If `$ARGUMENTS` contains both a dimension AND a value (e.g., `/plexor-settings routing eco`), apply it directly:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
node ~/.claude/plugins/plexor/commands/plexor-settings.js
|
|
10
|
+
node ~/.claude/plugins/plexor/commands/plexor-settings.js $ARGUMENTS
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Present the output to the user and STOP. Do NOT call any other tools.
|
|
14
|
+
|
|
15
|
+
**Step 2: If only a dimension was provided** (e.g., `/plexor-settings routing`), show current state then present a picker for that dimension:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
node ~/.claude/plugins/plexor/commands/plexor-settings.js $ARGUMENTS
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Then use **AskUserQuestion** based on which dimension:
|
|
22
|
+
|
|
23
|
+
**If dimension is "routing":**
|
|
24
|
+
- **Question**: "Which routing mode?"
|
|
25
|
+
- **Header**: "Routing"
|
|
26
|
+
- **Options**: eco (Recommended) — "Cheapest first", balanced — "Cost/quality balance", quality — "Premium models", passthrough — "Direct access"
|
|
27
|
+
|
|
28
|
+
**If dimension is "agent":**
|
|
29
|
+
- **Question**: "Which agent autonomy mode?"
|
|
30
|
+
- **Header**: "Agent mode"
|
|
31
|
+
- **Options**: supervised — "Confirm every action", autonomous (Recommended) — "Safe bounds", danger-full-auto — "No guardrails"
|
|
32
|
+
|
|
33
|
+
**If dimension is "provider":**
|
|
34
|
+
- **Question**: "Which LLM provider?"
|
|
35
|
+
- **Header**: "Provider"
|
|
36
|
+
- **Options**: auto (Recommended) — "Auto-select", anthropic — "Claude models", openai — "GPT models", deepseek — "DeepSeek models"
|
|
37
|
+
|
|
38
|
+
After the user selects, apply:
|
|
14
39
|
|
|
15
40
|
```bash
|
|
16
|
-
node ~/.claude/plugins/plexor/commands/plexor-settings.js
|
|
17
|
-
node ~/.claude/plugins/plexor/commands/plexor-settings.js timeout 10000
|
|
41
|
+
node ~/.claude/plugins/plexor/commands/plexor-settings.js <dimension> <selected_value>
|
|
18
42
|
```
|
|
19
43
|
|
|
20
|
-
|
|
44
|
+
Present the output and STOP.
|
|
45
|
+
|
|
46
|
+
**Step 3: If NO arguments were provided** (just `/plexor-settings`), show the dashboard:
|
|
21
47
|
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
- Run additional commands
|
|
26
|
-
- Ask follow-up questions
|
|
48
|
+
```bash
|
|
49
|
+
node ~/.claude/plugins/plexor/commands/plexor-settings.js
|
|
50
|
+
```
|
|
27
51
|
|
|
28
|
-
|
|
52
|
+
Present the output to the user and STOP. Do NOT call any other tools.
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { PLEXOR_DIR, CONFIG_PATH, DEFAULT_API_URL } = require('../lib/constants');
|
|
6
|
+
const PlexorClient = require('../lib/plexor-client');
|
|
7
|
+
const { settingsManager } = require('../lib/settings-manager');
|
|
8
|
+
const {
|
|
9
|
+
EXPECTED_VERIFY_RESPONSE,
|
|
10
|
+
VERIFY_PROMPT,
|
|
11
|
+
runClaudeRouteVerification
|
|
12
|
+
} = require('../lib/verify-route');
|
|
13
|
+
|
|
14
|
+
function isPlexorApiKey(value) {
|
|
15
|
+
return typeof value === 'string' && value.startsWith('plx_') && value.length >= 20;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function loadConfig() {
|
|
19
|
+
try {
|
|
20
|
+
if (!fs.existsSync(CONFIG_PATH)) {
|
|
21
|
+
return { version: 1, auth: {}, settings: {} };
|
|
22
|
+
}
|
|
23
|
+
const data = fs.readFileSync(CONFIG_PATH, 'utf8');
|
|
24
|
+
if (!data || data.trim() === '') {
|
|
25
|
+
return { version: 1, auth: {}, settings: {} };
|
|
26
|
+
}
|
|
27
|
+
const parsed = JSON.parse(data);
|
|
28
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
29
|
+
return { version: 1, auth: {}, settings: {} };
|
|
30
|
+
}
|
|
31
|
+
return parsed;
|
|
32
|
+
} catch {
|
|
33
|
+
return { version: 1, auth: {}, settings: {} };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function saveConfig(config) {
|
|
38
|
+
try {
|
|
39
|
+
if (!fs.existsSync(PLEXOR_DIR)) {
|
|
40
|
+
fs.mkdirSync(PLEXOR_DIR, { recursive: true, mode: 0o700 });
|
|
41
|
+
}
|
|
42
|
+
const tempPath = path.join(PLEXOR_DIR, `.config.${Date.now()}.tmp`);
|
|
43
|
+
fs.writeFileSync(tempPath, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
44
|
+
fs.renameSync(tempPath, CONFIG_PATH);
|
|
45
|
+
return true;
|
|
46
|
+
} catch (err) {
|
|
47
|
+
console.error(`Failed to save config: ${err.message}`);
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function readFromStdin() {
|
|
53
|
+
return new Promise((resolve, reject) => {
|
|
54
|
+
let data = '';
|
|
55
|
+
const timeout = setTimeout(() => {
|
|
56
|
+
reject(new Error('Timeout reading from stdin'));
|
|
57
|
+
}, 5000);
|
|
58
|
+
|
|
59
|
+
process.stdin.setEncoding('utf8');
|
|
60
|
+
process.stdin.on('data', (chunk) => {
|
|
61
|
+
data += chunk;
|
|
62
|
+
});
|
|
63
|
+
process.stdin.on('end', () => {
|
|
64
|
+
clearTimeout(timeout);
|
|
65
|
+
resolve(data.trim());
|
|
66
|
+
});
|
|
67
|
+
process.stdin.on('error', (err) => {
|
|
68
|
+
clearTimeout(timeout);
|
|
69
|
+
reject(err);
|
|
70
|
+
});
|
|
71
|
+
process.stdin.resume();
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function getKeySource(args, existingKey) {
|
|
76
|
+
if (process.env.PLEXOR_API_KEY) {
|
|
77
|
+
return { apiKey: process.env.PLEXOR_API_KEY, source: 'environment' };
|
|
78
|
+
}
|
|
79
|
+
if (!process.stdin.isTTY && args.length === 0) {
|
|
80
|
+
return { apiKey: null, source: 'stdin' };
|
|
81
|
+
}
|
|
82
|
+
if (args[0] && !args[0].startsWith('--')) {
|
|
83
|
+
return { apiKey: args[0], source: 'argument' };
|
|
84
|
+
}
|
|
85
|
+
if (existingKey) {
|
|
86
|
+
return { apiKey: existingKey, source: 'saved-config' };
|
|
87
|
+
}
|
|
88
|
+
return { apiKey: null, source: null };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function getGatewayLabel(apiUrl) {
|
|
92
|
+
return apiUrl.includes('staging') ? 'staging' : 'production';
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function updateHealth(config, state) {
|
|
96
|
+
config.health = {
|
|
97
|
+
installed: true,
|
|
98
|
+
connected: true,
|
|
99
|
+
routing_active: state.routingEnabled,
|
|
100
|
+
verified: state.verifyResult.ok,
|
|
101
|
+
verified_at: state.verifyResult.ok ? new Date().toISOString() : null,
|
|
102
|
+
verify_prompt: VERIFY_PROMPT,
|
|
103
|
+
verify_expected: EXPECTED_VERIFY_RESPONSE,
|
|
104
|
+
verify_error: state.verifyResult.ok ? null : state.verifyResult.reason,
|
|
105
|
+
gateway: state.gateway,
|
|
106
|
+
previous_auth_preserved: state.previousAuthPreserved
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function printUsage() {
|
|
111
|
+
console.log('Plexor setup is the guided first-run path.');
|
|
112
|
+
console.log('');
|
|
113
|
+
console.log('Provide a Plexor API key one of these ways:');
|
|
114
|
+
console.log(' /plexor-setup plx_...');
|
|
115
|
+
console.log(' echo "plx_..." | /plexor-setup');
|
|
116
|
+
console.log(' PLEXOR_API_KEY=plx_... /plexor-setup');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function printReceipt({ user, gateway, previousAuthPreserved, verifyResult }) {
|
|
120
|
+
const line = (content) => `│ ${String(content).slice(0, 43).padEnd(43)}│`;
|
|
121
|
+
|
|
122
|
+
console.log('┌─────────────────────────────────────────────┐');
|
|
123
|
+
console.log(line('Plexor setup complete'));
|
|
124
|
+
console.log('├─────────────────────────────────────────────┤');
|
|
125
|
+
console.log(line(`Connected: OK (${user.email || 'Unknown'})`));
|
|
126
|
+
console.log(line(`Routing Active: OK (${gateway})`));
|
|
127
|
+
console.log(line(`Verified: ${verifyResult.ok ? 'OK' : 'FAILED'}`));
|
|
128
|
+
console.log(line(`Previous Claude auth: ${previousAuthPreserved ? 'Saved' : 'None found'}`));
|
|
129
|
+
console.log('├─────────────────────────────────────────────┤');
|
|
130
|
+
if (verifyResult.ok) {
|
|
131
|
+
console.log(line('Claude is now routed through Plexor'));
|
|
132
|
+
console.log(line('Logout/uninstall restores prior auth'));
|
|
133
|
+
console.log(line('Next: Run /plexor-status for health + stats'));
|
|
134
|
+
} else {
|
|
135
|
+
console.log(line('Claude routing was configured'));
|
|
136
|
+
console.log(line('Verification did not pass'));
|
|
137
|
+
console.log(line('Next: Run /plexor-setup again to repair'));
|
|
138
|
+
}
|
|
139
|
+
console.log('└─────────────────────────────────────────────┘');
|
|
140
|
+
|
|
141
|
+
if (!verifyResult.ok) {
|
|
142
|
+
console.log('');
|
|
143
|
+
console.log(`Verification failed: ${verifyResult.reason}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function main() {
|
|
148
|
+
const args = process.argv.slice(2);
|
|
149
|
+
const skipVerify = args.includes('--skip-verify');
|
|
150
|
+
const config = loadConfig();
|
|
151
|
+
const existingKey = config.auth?.api_key || '';
|
|
152
|
+
const keyInput = getKeySource(args.filter(arg => arg !== '--skip-verify'), existingKey);
|
|
153
|
+
let apiKey = keyInput.apiKey;
|
|
154
|
+
|
|
155
|
+
if (!apiKey && keyInput.source === 'stdin') {
|
|
156
|
+
try {
|
|
157
|
+
apiKey = await readFromStdin();
|
|
158
|
+
} catch {
|
|
159
|
+
apiKey = null;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (!apiKey) {
|
|
164
|
+
printUsage();
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (!isPlexorApiKey(apiKey)) {
|
|
169
|
+
console.error('Error: Plexor API keys must start with "plx_" and be at least 20 characters.');
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const apiUrl = config.settings?.apiUrl || DEFAULT_API_URL;
|
|
174
|
+
const client = new PlexorClient({ apiKey, baseUrl: apiUrl });
|
|
175
|
+
|
|
176
|
+
let user;
|
|
177
|
+
try {
|
|
178
|
+
user = await client.getUser();
|
|
179
|
+
} catch (err) {
|
|
180
|
+
console.error(`Error: ${err.message}`);
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const updatedConfig = {
|
|
185
|
+
...config,
|
|
186
|
+
version: 1,
|
|
187
|
+
auth: {
|
|
188
|
+
...(config.auth || {}),
|
|
189
|
+
api_key: apiKey,
|
|
190
|
+
mode: 'api_key',
|
|
191
|
+
authenticated_at: new Date().toISOString()
|
|
192
|
+
},
|
|
193
|
+
settings: {
|
|
194
|
+
...(config.settings || {}),
|
|
195
|
+
enabled: true,
|
|
196
|
+
apiUrl,
|
|
197
|
+
preferred_provider: config.settings?.preferred_provider || 'auto',
|
|
198
|
+
mode: config.settings?.mode || 'balanced',
|
|
199
|
+
localCacheEnabled: config.settings?.localCacheEnabled ?? true
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
if (!saveConfig(updatedConfig)) {
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const routingEnabled = settingsManager.enablePlexorRouting(apiKey, {
|
|
208
|
+
useStaging: apiUrl.includes('staging')
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
if (!routingEnabled) {
|
|
212
|
+
console.error('Error: Plexor saved your key but could not activate Claude routing.');
|
|
213
|
+
console.error('Run /plexor-setup again after fixing ~/.claude/settings.json permissions.');
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const currentSettings = settingsManager.load();
|
|
218
|
+
const previousAuthPreserved = Boolean(
|
|
219
|
+
currentSettings.env?.PLEXOR_PREVIOUS_ANTHROPIC_API_KEY ||
|
|
220
|
+
currentSettings.env?.PLEXOR_PREVIOUS_ANTHROPIC_AUTH_TOKEN
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
const verifyResult = skipVerify
|
|
224
|
+
? { ok: true, reason: '', stdout: EXPECTED_VERIFY_RESPONSE, stderr: '', code: 0 }
|
|
225
|
+
: runClaudeRouteVerification();
|
|
226
|
+
|
|
227
|
+
updateHealth(updatedConfig, {
|
|
228
|
+
gateway: getGatewayLabel(apiUrl),
|
|
229
|
+
previousAuthPreserved,
|
|
230
|
+
routingEnabled,
|
|
231
|
+
verifyResult
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
if (!saveConfig(updatedConfig)) {
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
printReceipt({
|
|
239
|
+
user,
|
|
240
|
+
gateway: getGatewayLabel(apiUrl),
|
|
241
|
+
previousAuthPreserved,
|
|
242
|
+
verifyResult
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
if (!verifyResult.ok) {
|
|
246
|
+
process.exit(1);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
main().catch((err) => {
|
|
251
|
+
console.error(`Error: ${err.message}`);
|
|
252
|
+
process.exit(1);
|
|
253
|
+
});
|
package/commands/plexor-setup.md
CHANGED
|
@@ -1,172 +1,28 @@
|
|
|
1
|
+
description: Guided first-run setup for Plexor with Claude Code (user)
|
|
1
2
|
---
|
|
2
|
-
description: First-time setup wizard for Plexor with Claude Code (user)
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Plexor Setup Wizard
|
|
6
|
-
|
|
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.
|
|
10
|
-
|
|
11
|
-
## Steps
|
|
12
3
|
|
|
13
|
-
**
|
|
4
|
+
**RULE: Execute this workflow EXACTLY ONCE. After the Bash tool returns output, your ONLY action is to present that output to the user. DO NOT restart the workflow.**
|
|
14
5
|
|
|
15
|
-
|
|
16
|
-
Also check `~/.claude/settings.json` for routing status.
|
|
6
|
+
Plexor setup is the primary human setup flow.
|
|
17
7
|
|
|
18
|
-
If
|
|
19
|
-
```
|
|
20
|
-
Plexor Setup
|
|
21
|
-
============
|
|
22
|
-
Already configured!
|
|
23
|
-
|
|
24
|
-
API URL: [apiUrl from config]
|
|
25
|
-
Mode: [mode from config]
|
|
26
|
-
Status: [Enabled/Disabled]
|
|
27
|
-
Claude Routing: [Active/Inactive]
|
|
28
|
-
|
|
29
|
-
Run /plexor-status to see your usage.
|
|
30
|
-
Run /plexor-settings to modify configuration.
|
|
31
|
-
Run /plexor-enabled off to disable routing.
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
**Step 2: Ask about Claude subscription**
|
|
35
|
-
|
|
36
|
-
Use the AskUserQuestion tool:
|
|
37
|
-
|
|
38
|
-
Question: "How do you pay for Claude usage?"
|
|
39
|
-
Header: "Billing"
|
|
40
|
-
Options:
|
|
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
|
|
43
|
-
|
|
44
|
-
**Step 3A: Claude MAX User Setup**
|
|
45
|
-
|
|
46
|
-
If user selected "Yes, I have Claude MAX":
|
|
47
|
-
|
|
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`:
|
|
54
|
-
```json
|
|
55
|
-
{
|
|
56
|
-
"version": 1,
|
|
57
|
-
"auth": {
|
|
58
|
-
"api_key": "[user's Plexor key]",
|
|
59
|
-
"mode": "oauth_passthrough",
|
|
60
|
-
"authenticated_at": "[current ISO timestamp]"
|
|
61
|
-
},
|
|
62
|
-
"settings": {
|
|
63
|
-
"enabled": true,
|
|
64
|
-
"apiUrl": "https://staging.api.plexor.dev",
|
|
65
|
-
"mode": "balanced",
|
|
66
|
-
"localCacheEnabled": true
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
3. Use the Write tool to update `~/.claude/settings.json` env block:
|
|
72
|
-
```json
|
|
73
|
-
{
|
|
74
|
-
"env": {
|
|
75
|
-
"ANTHROPIC_BASE_URL": "https://staging.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:
|
|
83
|
-
```
|
|
84
|
-
Plexor Setup - Claude MAX User
|
|
85
|
-
==============================
|
|
86
|
-
Setup Complete! No manual configuration needed.
|
|
87
|
-
|
|
88
|
-
What was configured:
|
|
89
|
-
- ~/.plexor/config.json (Plexor plugin settings)
|
|
90
|
-
- ~/.claude/settings.json (automatic Claude Code routing)
|
|
91
|
-
|
|
92
|
-
How it works:
|
|
93
|
-
- All Claude Code sessions now route through Plexor
|
|
94
|
-
- Your MAX subscription OAuth token is passed through
|
|
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
|
|
102
|
-
|
|
103
|
-
Changes take effect immediately in all Claude Code sessions!
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
**Step 3B: API Key User Setup**
|
|
107
|
-
|
|
108
|
-
If user selected "No, I'll use a Plexor API key":
|
|
109
|
-
|
|
110
|
-
1. Ask for their Plexor API key:
|
|
111
|
-
"Please provide your Plexor API key (starts with 'plx_')."
|
|
112
|
-
"Get one at: https://plexor.dev/dashboard"
|
|
113
|
-
|
|
114
|
-
2. Once they provide the key, use the Write tool to create `~/.plexor/config.json`:
|
|
115
|
-
```json
|
|
116
|
-
{
|
|
117
|
-
"version": 1,
|
|
118
|
-
"auth": {
|
|
119
|
-
"api_key": "[user's API key]",
|
|
120
|
-
"mode": "api_key",
|
|
121
|
-
"authenticated_at": "[current ISO timestamp]"
|
|
122
|
-
},
|
|
123
|
-
"settings": {
|
|
124
|
-
"enabled": true,
|
|
125
|
-
"apiUrl": "https://staging.api.plexor.dev",
|
|
126
|
-
"preferred_provider": "auto",
|
|
127
|
-
"mode": "balanced",
|
|
128
|
-
"localCacheEnabled": true
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
3. Use the Write tool to update `~/.claude/settings.json` env block:
|
|
134
|
-
```json
|
|
135
|
-
{
|
|
136
|
-
"env": {
|
|
137
|
-
"ANTHROPIC_BASE_URL": "https://staging.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.
|
|
8
|
+
If `$ARGUMENTS` already contains a Plexor API key (`plx_...`), run:
|
|
143
9
|
|
|
144
|
-
|
|
10
|
+
```bash
|
|
11
|
+
node ~/.claude/plugins/plexor/commands/plexor-setup.js $ARGUMENTS
|
|
145
12
|
```
|
|
146
|
-
Plexor Setup - API Key User
|
|
147
|
-
===========================
|
|
148
|
-
Setup Complete! No manual configuration needed.
|
|
149
13
|
|
|
150
|
-
|
|
151
|
-
- ~/.plexor/config.json (Plexor plugin settings)
|
|
152
|
-
- ~/.claude/settings.json (automatic Claude Code routing)
|
|
14
|
+
If the user did not provide a key yet, ask them:
|
|
153
15
|
|
|
154
|
-
|
|
155
|
-
- All Claude Code sessions now route through Plexor
|
|
156
|
-
- Plexor picks the best provider (can save up to 90%)
|
|
157
|
-
- Your usage is tracked and optimized
|
|
16
|
+
`Please paste your Plexor API key (starts with plx_). You can get one at https://plexor.dev/dashboard.`
|
|
158
17
|
|
|
159
|
-
|
|
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
|
|
18
|
+
After the user replies with the key, run:
|
|
164
19
|
|
|
165
|
-
|
|
20
|
+
```bash
|
|
21
|
+
node ~/.claude/plugins/plexor/commands/plexor-setup.js <user_key>
|
|
166
22
|
```
|
|
167
23
|
|
|
168
|
-
|
|
169
|
-
-
|
|
170
|
-
-
|
|
171
|
-
-
|
|
172
|
-
-
|
|
24
|
+
This command:
|
|
25
|
+
- saves the Plexor key
|
|
26
|
+
- routes Claude through the Plexor staging gateway
|
|
27
|
+
- preserves prior direct Claude auth for restore on logout/uninstall
|
|
28
|
+
- runs a deterministic Claude verification step
|