@plexor-dev/claude-code-plugin 0.1.0-beta.20 → 0.1.0-beta.21
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-config.js +170 -0
- package/commands/plexor-enabled.js +91 -0
- package/commands/plexor-login.js +169 -0
- package/commands/plexor-logout.js +92 -0
- package/commands/plexor-mode.js +107 -0
- package/commands/plexor-provider.js +110 -0
- package/commands/plexor-settings.js +155 -0
- package/commands/plexor-status.js +0 -0
- package/lib/plexor-client.js +1 -1
- package/package.json +11 -1
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Plexor Config Command
|
|
5
|
+
* Display raw configuration (for debugging)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
const CONFIG_PATH = path.join(process.env.HOME, '.plexor', 'config.json');
|
|
12
|
+
const SESSION_PATH = path.join(process.env.HOME, '.plexor', 'session.json');
|
|
13
|
+
const CACHE_PATH = path.join(process.env.HOME, '.plexor', 'cache.json');
|
|
14
|
+
const PLEXOR_DIR = path.join(process.env.HOME, '.plexor');
|
|
15
|
+
|
|
16
|
+
function fileExists(filePath) {
|
|
17
|
+
try {
|
|
18
|
+
return fs.existsSync(filePath);
|
|
19
|
+
} catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getFileSize(filePath) {
|
|
25
|
+
try {
|
|
26
|
+
const stats = fs.statSync(filePath);
|
|
27
|
+
return stats.size;
|
|
28
|
+
} catch {
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function formatBytes(bytes) {
|
|
34
|
+
if (bytes === 0) return '0 B';
|
|
35
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
36
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
37
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function loadConfig() {
|
|
41
|
+
try {
|
|
42
|
+
if (!fs.existsSync(CONFIG_PATH)) {
|
|
43
|
+
return { error: 'not_found', message: 'Config file does not exist' };
|
|
44
|
+
}
|
|
45
|
+
const data = fs.readFileSync(CONFIG_PATH, 'utf8');
|
|
46
|
+
return { config: JSON.parse(data) };
|
|
47
|
+
} catch (err) {
|
|
48
|
+
if (err.code === 'ENOENT') {
|
|
49
|
+
return { error: 'not_found', message: 'Config file does not exist' };
|
|
50
|
+
}
|
|
51
|
+
if (err.code === 'EACCES') {
|
|
52
|
+
return { error: 'permission', message: 'Permission denied reading config' };
|
|
53
|
+
}
|
|
54
|
+
if (err instanceof SyntaxError) {
|
|
55
|
+
return { error: 'invalid_json', message: 'Config file contains invalid JSON' };
|
|
56
|
+
}
|
|
57
|
+
return { error: 'unknown', message: err.message };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function maskApiKey(key) {
|
|
62
|
+
if (!key) return 'not set';
|
|
63
|
+
if (key.length <= 12) return '***masked***';
|
|
64
|
+
return key.substring(0, 8) + '...' + key.substring(key.length - 4);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function main() {
|
|
68
|
+
const args = process.argv.slice(2);
|
|
69
|
+
const showRaw = args.includes('--raw') || args.includes('-r');
|
|
70
|
+
const showPaths = args.includes('--paths') || args.includes('-p');
|
|
71
|
+
|
|
72
|
+
// Show paths only
|
|
73
|
+
if (showPaths) {
|
|
74
|
+
console.log(`┌─────────────────────────────────────────────┐`);
|
|
75
|
+
console.log(`│ Plexor File Paths │`);
|
|
76
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
77
|
+
console.log(`│ Directory: ${PLEXOR_DIR.substring(0, 31).padEnd(31)}│`);
|
|
78
|
+
console.log(`│ Config: ${CONFIG_PATH.substring(0, 34).padEnd(34)}│`);
|
|
79
|
+
console.log(`│ Session: ${SESSION_PATH.substring(0, 33).padEnd(33)}│`);
|
|
80
|
+
console.log(`│ Cache: ${CACHE_PATH.substring(0, 35).padEnd(35)}│`);
|
|
81
|
+
console.log(`└─────────────────────────────────────────────┘`);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const result = loadConfig();
|
|
86
|
+
|
|
87
|
+
if (result.error) {
|
|
88
|
+
const errorMessages = {
|
|
89
|
+
not_found: 'Config file does not exist',
|
|
90
|
+
permission: 'Permission denied reading config file',
|
|
91
|
+
invalid_json: 'Config file contains invalid JSON (corrupted?)',
|
|
92
|
+
unknown: result.message || 'Unknown error'
|
|
93
|
+
};
|
|
94
|
+
const errorMsg = errorMessages[result.error] || result.message;
|
|
95
|
+
const suggestion = result.error === 'invalid_json'
|
|
96
|
+
? 'Try: rm ~/.plexor/config.json && /plexor-login'
|
|
97
|
+
: 'Run /plexor-login to create configuration.';
|
|
98
|
+
|
|
99
|
+
console.log(`┌─────────────────────────────────────────────┐`);
|
|
100
|
+
console.log(`│ Configuration Error │`);
|
|
101
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
102
|
+
console.log(`│ Error: ${result.error.padEnd(35)}│`);
|
|
103
|
+
console.log(`│ ${errorMsg.substring(0, 42).padEnd(42)}│`);
|
|
104
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
105
|
+
console.log(`│ ${suggestion.substring(0, 42).padEnd(42)}│`);
|
|
106
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
107
|
+
console.log(`│ Expected path: │`);
|
|
108
|
+
console.log(`│ ${CONFIG_PATH.substring(0, 42).padEnd(42)}│`);
|
|
109
|
+
console.log(`└─────────────────────────────────────────────┘`);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const config = result.config;
|
|
114
|
+
|
|
115
|
+
// Show raw JSON
|
|
116
|
+
if (showRaw) {
|
|
117
|
+
// Mask API key in raw output
|
|
118
|
+
const safeConfig = JSON.parse(JSON.stringify(config));
|
|
119
|
+
if (safeConfig.auth?.api_key) {
|
|
120
|
+
safeConfig.auth.api_key = maskApiKey(safeConfig.auth.api_key);
|
|
121
|
+
}
|
|
122
|
+
console.log(JSON.stringify(safeConfig, null, 2));
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Show formatted config info
|
|
127
|
+
const configSize = getFileSize(CONFIG_PATH);
|
|
128
|
+
const sessionSize = getFileSize(SESSION_PATH);
|
|
129
|
+
const cacheSize = getFileSize(CACHE_PATH);
|
|
130
|
+
const hasSession = fileExists(SESSION_PATH);
|
|
131
|
+
const hasCache = fileExists(CACHE_PATH);
|
|
132
|
+
|
|
133
|
+
console.log(`┌─────────────────────────────────────────────┐`);
|
|
134
|
+
console.log(`│ Plexor Configuration │`);
|
|
135
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
136
|
+
console.log(`│ Version: ${(config.version || 1).toString().padEnd(33)}│`);
|
|
137
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
138
|
+
console.log(`│ Authentication │`);
|
|
139
|
+
console.log(`│ └── API Key: ${maskApiKey(config.auth?.api_key).padEnd(29)}│`);
|
|
140
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
141
|
+
console.log(`│ Settings │`);
|
|
142
|
+
|
|
143
|
+
const settings = config.settings || {};
|
|
144
|
+
const settingEntries = [
|
|
145
|
+
['enabled', settings.enabled ?? false],
|
|
146
|
+
['mode', settings.mode || 'balanced'],
|
|
147
|
+
['preferred_provider', settings.preferred_provider || 'auto'],
|
|
148
|
+
['apiUrl', settings.apiUrl || 'https://api.plexor.dev'],
|
|
149
|
+
['timeout', (settings.timeout || 5000) + 'ms'],
|
|
150
|
+
['localCacheEnabled', settings.localCacheEnabled ?? false]
|
|
151
|
+
];
|
|
152
|
+
|
|
153
|
+
for (const [key, value] of settingEntries) {
|
|
154
|
+
const displayValue = String(value).substring(0, 25);
|
|
155
|
+
console.log(`│ ├── ${key.padEnd(18)} ${displayValue.padEnd(18)}│`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
159
|
+
console.log(`│ Files │`);
|
|
160
|
+
console.log(`│ ├── config.json: ${formatBytes(configSize).padEnd(24)}│`);
|
|
161
|
+
console.log(`│ ├── session.json: ${(hasSession ? formatBytes(sessionSize) : 'not found').padEnd(23)}│`);
|
|
162
|
+
console.log(`│ └── cache.json: ${(hasCache ? formatBytes(cacheSize) : 'not found').padEnd(25)}│`);
|
|
163
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
164
|
+
console.log(`│ Options: │`);
|
|
165
|
+
console.log(`│ /plexor-config --raw Show raw JSON │`);
|
|
166
|
+
console.log(`│ /plexor-config --paths Show file paths │`);
|
|
167
|
+
console.log(`└─────────────────────────────────────────────┘`);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
main();
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Plexor Enabled Command
|
|
5
|
+
* Enable or disable Plexor optimization proxy
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
const CONFIG_PATH = path.join(process.env.HOME, '.plexor', 'config.json');
|
|
12
|
+
const PLEXOR_DIR = path.join(process.env.HOME, '.plexor');
|
|
13
|
+
|
|
14
|
+
function loadConfig() {
|
|
15
|
+
try {
|
|
16
|
+
const data = fs.readFileSync(CONFIG_PATH, 'utf8');
|
|
17
|
+
return JSON.parse(data);
|
|
18
|
+
} catch {
|
|
19
|
+
return { version: 1, auth: {}, settings: {} };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function saveConfig(config) {
|
|
24
|
+
if (!fs.existsSync(PLEXOR_DIR)) {
|
|
25
|
+
fs.mkdirSync(PLEXOR_DIR, { recursive: true, mode: 0o700 });
|
|
26
|
+
}
|
|
27
|
+
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function main() {
|
|
31
|
+
const args = process.argv.slice(2);
|
|
32
|
+
const config = loadConfig();
|
|
33
|
+
const currentEnabled = config.settings?.enabled ?? false;
|
|
34
|
+
|
|
35
|
+
// No args - show current status
|
|
36
|
+
if (args.length === 0) {
|
|
37
|
+
const status = currentEnabled ? '● Enabled' : '○ Disabled';
|
|
38
|
+
console.log(`┌─────────────────────────────────────────────┐`);
|
|
39
|
+
console.log(`│ Plexor Proxy Status │`);
|
|
40
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
41
|
+
console.log(`│ Status: ${status.padEnd(34)}│`);
|
|
42
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
43
|
+
console.log(`│ Usage: │`);
|
|
44
|
+
console.log(`│ /plexor-enabled true - Enable proxy │`);
|
|
45
|
+
console.log(`│ /plexor-enabled false - Disable proxy │`);
|
|
46
|
+
console.log(`│ /plexor-enabled on - Enable proxy │`);
|
|
47
|
+
console.log(`│ /plexor-enabled off - Disable proxy │`);
|
|
48
|
+
console.log(`└─────────────────────────────────────────────┘`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const arg = args[0].toLowerCase();
|
|
53
|
+
let newEnabled;
|
|
54
|
+
|
|
55
|
+
if (['true', 'on', 'yes', '1', 'enable'].includes(arg)) {
|
|
56
|
+
newEnabled = true;
|
|
57
|
+
} else if (['false', 'off', 'no', '0', 'disable'].includes(arg)) {
|
|
58
|
+
newEnabled = false;
|
|
59
|
+
} else {
|
|
60
|
+
console.error(`Error: Invalid value "${args[0]}"`);
|
|
61
|
+
console.error(`Use: true/false, on/off, yes/no, enable/disable`);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (newEnabled === currentEnabled) {
|
|
66
|
+
const state = currentEnabled ? 'enabled' : 'disabled';
|
|
67
|
+
console.log(`Plexor proxy is already ${state}`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
config.settings = config.settings || {};
|
|
72
|
+
config.settings.enabled = newEnabled;
|
|
73
|
+
saveConfig(config);
|
|
74
|
+
|
|
75
|
+
const newStatus = newEnabled ? '● Enabled' : '○ Disabled';
|
|
76
|
+
const prevStatus = currentEnabled ? 'Enabled' : 'Disabled';
|
|
77
|
+
const message = newEnabled
|
|
78
|
+
? 'All requests will be routed through Plexor'
|
|
79
|
+
: 'Requests will go directly to providers';
|
|
80
|
+
|
|
81
|
+
console.log(`┌─────────────────────────────────────────────┐`);
|
|
82
|
+
console.log(`│ ✓ Plexor Proxy Updated │`);
|
|
83
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
84
|
+
console.log(`│ Previous: ${prevStatus.padEnd(32)}│`);
|
|
85
|
+
console.log(`│ New: ${newStatus.padEnd(37)}│`);
|
|
86
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
87
|
+
console.log(`│ ${message.padEnd(42)}│`);
|
|
88
|
+
console.log(`└─────────────────────────────────────────────┘`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
main();
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Plexor Login Command
|
|
5
|
+
* Authenticate with Plexor API
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const https = require('https');
|
|
11
|
+
const http = require('http');
|
|
12
|
+
|
|
13
|
+
const CONFIG_PATH = path.join(process.env.HOME, '.plexor', 'config.json');
|
|
14
|
+
const PLEXOR_DIR = path.join(process.env.HOME, '.plexor');
|
|
15
|
+
const DEFAULT_API_URL = 'https://api.plexor.dev';
|
|
16
|
+
|
|
17
|
+
function loadConfig() {
|
|
18
|
+
try {
|
|
19
|
+
const data = fs.readFileSync(CONFIG_PATH, 'utf8');
|
|
20
|
+
return JSON.parse(data);
|
|
21
|
+
} catch {
|
|
22
|
+
return { version: 1, auth: {}, settings: {} };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function saveConfig(config) {
|
|
27
|
+
if (!fs.existsSync(PLEXOR_DIR)) {
|
|
28
|
+
fs.mkdirSync(PLEXOR_DIR, { recursive: true, mode: 0o700 });
|
|
29
|
+
}
|
|
30
|
+
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function validateApiKey(apiUrl, apiKey) {
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
const url = new URL(`${apiUrl}/v1/user`);
|
|
36
|
+
const isHttps = url.protocol === 'https:';
|
|
37
|
+
const lib = isHttps ? https : http;
|
|
38
|
+
|
|
39
|
+
const options = {
|
|
40
|
+
hostname: url.hostname,
|
|
41
|
+
port: url.port || (isHttps ? 443 : 80),
|
|
42
|
+
path: url.pathname,
|
|
43
|
+
method: 'GET',
|
|
44
|
+
headers: {
|
|
45
|
+
'X-Plexor-Key': apiKey
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const req = lib.request(options, (res) => {
|
|
50
|
+
let data = '';
|
|
51
|
+
res.on('data', chunk => data += chunk);
|
|
52
|
+
res.on('end', () => {
|
|
53
|
+
if (res.statusCode === 200) {
|
|
54
|
+
try {
|
|
55
|
+
resolve(JSON.parse(data));
|
|
56
|
+
} catch {
|
|
57
|
+
reject(new Error('Invalid response from server'));
|
|
58
|
+
}
|
|
59
|
+
} else if (res.statusCode === 401) {
|
|
60
|
+
reject(new Error('Invalid API key'));
|
|
61
|
+
} else {
|
|
62
|
+
reject(new Error(`Server error: ${res.statusCode}`));
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
req.on('error', (err) => reject(new Error(`Connection failed: ${err.message}`)));
|
|
68
|
+
req.setTimeout(10000, () => {
|
|
69
|
+
req.destroy();
|
|
70
|
+
reject(new Error('Connection timeout'));
|
|
71
|
+
});
|
|
72
|
+
req.end();
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function promptForApiKey() {
|
|
77
|
+
const rl = readline.createInterface({
|
|
78
|
+
input: process.stdin,
|
|
79
|
+
output: process.stdout
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
return new Promise((resolve) => {
|
|
83
|
+
rl.question('Enter your Plexor API key: ', (answer) => {
|
|
84
|
+
rl.close();
|
|
85
|
+
resolve(answer.trim());
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function main() {
|
|
91
|
+
const args = process.argv.slice(2);
|
|
92
|
+
let apiKey = args[0];
|
|
93
|
+
|
|
94
|
+
// Check for existing login
|
|
95
|
+
const config = loadConfig();
|
|
96
|
+
const existingKey = config.auth?.api_key;
|
|
97
|
+
|
|
98
|
+
if (existingKey && !apiKey) {
|
|
99
|
+
console.log(`┌─────────────────────────────────────────────┐`);
|
|
100
|
+
console.log(`│ Already Logged In │`);
|
|
101
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
102
|
+
console.log(`│ API Key: ${(existingKey.substring(0, 8) + '...').padEnd(33)}│`);
|
|
103
|
+
console.log(`│ To re-login, provide a new key: │`);
|
|
104
|
+
console.log(`│ /plexor-login <api-key> │`);
|
|
105
|
+
console.log(`│ To logout: │`);
|
|
106
|
+
console.log(`│ /plexor-logout │`);
|
|
107
|
+
console.log(`└─────────────────────────────────────────────┘`);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// If no key provided, prompt for it
|
|
112
|
+
if (!apiKey) {
|
|
113
|
+
console.log(`┌─────────────────────────────────────────────┐`);
|
|
114
|
+
console.log(`│ Plexor Login │`);
|
|
115
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
116
|
+
console.log(`│ Get your API key at: │`);
|
|
117
|
+
console.log(`│ https://plexor.dev/dashboard/api-keys │`);
|
|
118
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
119
|
+
console.log(`│ Usage: /plexor-login <api-key> │`);
|
|
120
|
+
console.log(`└─────────────────────────────────────────────┘`);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Validate key format
|
|
125
|
+
if (!apiKey.startsWith('plx_') || apiKey.length < 20) {
|
|
126
|
+
console.error(`Error: Invalid API key format`);
|
|
127
|
+
console.error(`API keys start with "plx_" and are at least 20 characters`);
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const apiUrl = config.settings?.apiUrl || DEFAULT_API_URL;
|
|
132
|
+
|
|
133
|
+
console.log('Validating API key...');
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const user = await validateApiKey(apiUrl, apiKey);
|
|
137
|
+
|
|
138
|
+
config.auth = config.auth || {};
|
|
139
|
+
config.auth.api_key = apiKey;
|
|
140
|
+
config.settings = config.settings || {};
|
|
141
|
+
config.settings.enabled = true;
|
|
142
|
+
saveConfig(config);
|
|
143
|
+
|
|
144
|
+
const email = user.email || 'Unknown';
|
|
145
|
+
const tier = user.tier?.name || 'Free';
|
|
146
|
+
|
|
147
|
+
console.log(`┌─────────────────────────────────────────────┐`);
|
|
148
|
+
console.log(`│ ✓ Login Successful │`);
|
|
149
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
150
|
+
console.log(`│ Email: ${email.substring(0, 35).padEnd(35)}│`);
|
|
151
|
+
console.log(`│ Tier: ${tier.padEnd(36)}│`);
|
|
152
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
153
|
+
console.log(`│ Plexor proxy is now enabled. │`);
|
|
154
|
+
console.log(`│ Run /plexor-status to see your stats. │`);
|
|
155
|
+
console.log(`└─────────────────────────────────────────────┘`);
|
|
156
|
+
} catch (err) {
|
|
157
|
+
console.error(`┌─────────────────────────────────────────────┐`);
|
|
158
|
+
console.error(`│ ✗ Login Failed │`);
|
|
159
|
+
console.error(`├─────────────────────────────────────────────┤`);
|
|
160
|
+
console.error(`│ ${err.message.padEnd(42)}│`);
|
|
161
|
+
console.error(`└─────────────────────────────────────────────┘`);
|
|
162
|
+
process.exit(1);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
main().catch(err => {
|
|
167
|
+
console.error('Error:', err.message);
|
|
168
|
+
process.exit(1);
|
|
169
|
+
});
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Plexor Logout Command
|
|
5
|
+
* Clear Plexor credentials and disable proxy
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
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');
|
|
15
|
+
|
|
16
|
+
function loadConfig() {
|
|
17
|
+
try {
|
|
18
|
+
const data = fs.readFileSync(CONFIG_PATH, 'utf8');
|
|
19
|
+
return JSON.parse(data);
|
|
20
|
+
} catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function saveConfig(config) {
|
|
26
|
+
if (!fs.existsSync(PLEXOR_DIR)) {
|
|
27
|
+
fs.mkdirSync(PLEXOR_DIR, { recursive: true, mode: 0o700 });
|
|
28
|
+
}
|
|
29
|
+
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function deleteFile(filePath) {
|
|
33
|
+
try {
|
|
34
|
+
if (fs.existsSync(filePath)) {
|
|
35
|
+
fs.unlinkSync(filePath);
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
} catch {
|
|
39
|
+
// Ignore errors
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function main() {
|
|
45
|
+
const args = process.argv.slice(2);
|
|
46
|
+
const config = loadConfig();
|
|
47
|
+
|
|
48
|
+
if (!config || !config.auth?.api_key) {
|
|
49
|
+
console.log(`┌─────────────────────────────────────────────┐`);
|
|
50
|
+
console.log(`│ Not Logged In │`);
|
|
51
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
52
|
+
console.log(`│ No active Plexor session found. │`);
|
|
53
|
+
console.log(`│ Run /plexor-login to authenticate. │`);
|
|
54
|
+
console.log(`└─────────────────────────────────────────────┘`);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const clearCache = args.includes('--clear-cache') || args.includes('-c');
|
|
59
|
+
|
|
60
|
+
// Clear credentials
|
|
61
|
+
delete config.auth.api_key;
|
|
62
|
+
config.settings = config.settings || {};
|
|
63
|
+
config.settings.enabled = false;
|
|
64
|
+
saveConfig(config);
|
|
65
|
+
|
|
66
|
+
// Clear session
|
|
67
|
+
deleteFile(SESSION_PATH);
|
|
68
|
+
|
|
69
|
+
// Optionally clear cache
|
|
70
|
+
let cacheCleared = false;
|
|
71
|
+
if (clearCache) {
|
|
72
|
+
cacheCleared = deleteFile(CACHE_PATH);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
console.log(`┌─────────────────────────────────────────────┐`);
|
|
76
|
+
console.log(`│ ✓ Logged Out │`);
|
|
77
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
78
|
+
console.log(`│ ✓ API key removed │`);
|
|
79
|
+
console.log(`│ ✓ Plexor proxy disabled │`);
|
|
80
|
+
console.log(`│ ✓ Session cleared │`);
|
|
81
|
+
if (clearCache) {
|
|
82
|
+
console.log(`│ ${cacheCleared ? '✓' : '○'} Cache cleared │`);
|
|
83
|
+
}
|
|
84
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
85
|
+
console.log(`│ Run /plexor-login to re-authenticate. │`);
|
|
86
|
+
if (!clearCache) {
|
|
87
|
+
console.log(`│ Use --clear-cache to also clear cache. │`);
|
|
88
|
+
}
|
|
89
|
+
console.log(`└─────────────────────────────────────────────┘`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
main();
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Plexor Mode Command
|
|
5
|
+
* Set optimization mode: eco, balanced, quality, passthrough
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
const CONFIG_PATH = path.join(process.env.HOME, '.plexor', 'config.json');
|
|
12
|
+
const PLEXOR_DIR = path.join(process.env.HOME, '.plexor');
|
|
13
|
+
|
|
14
|
+
const VALID_MODES = ['eco', 'balanced', 'quality', 'passthrough'];
|
|
15
|
+
|
|
16
|
+
const MODE_INFO = {
|
|
17
|
+
eco: {
|
|
18
|
+
description: 'Maximum savings (~$0.04/1M tokens)',
|
|
19
|
+
models: 'Ministral 3B, small models'
|
|
20
|
+
},
|
|
21
|
+
balanced: {
|
|
22
|
+
description: 'Good balance (~$0.15/1M tokens)',
|
|
23
|
+
models: 'DeepSeek, Gemini Flash, Mistral Small'
|
|
24
|
+
},
|
|
25
|
+
quality: {
|
|
26
|
+
description: 'Premium models (~$5/1M tokens)',
|
|
27
|
+
models: 'Claude Opus, Gemini Pro, Mistral Large'
|
|
28
|
+
},
|
|
29
|
+
passthrough: {
|
|
30
|
+
description: 'No optimization',
|
|
31
|
+
models: 'Direct to requested model'
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
function loadConfig() {
|
|
36
|
+
try {
|
|
37
|
+
const data = fs.readFileSync(CONFIG_PATH, 'utf8');
|
|
38
|
+
return JSON.parse(data);
|
|
39
|
+
} catch {
|
|
40
|
+
return { version: 1, auth: {}, settings: {} };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function saveConfig(config) {
|
|
45
|
+
if (!fs.existsSync(PLEXOR_DIR)) {
|
|
46
|
+
fs.mkdirSync(PLEXOR_DIR, { recursive: true, mode: 0o700 });
|
|
47
|
+
}
|
|
48
|
+
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function main() {
|
|
52
|
+
const args = process.argv.slice(2);
|
|
53
|
+
const config = loadConfig();
|
|
54
|
+
const currentMode = config.settings?.mode || 'balanced';
|
|
55
|
+
|
|
56
|
+
// No args - show current mode and options
|
|
57
|
+
if (args.length === 0) {
|
|
58
|
+
console.log(`┌─────────────────────────────────────────────┐`);
|
|
59
|
+
console.log(`│ Plexor Optimization Mode │`);
|
|
60
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
61
|
+
console.log(`│ Current: ${currentMode.padEnd(33)}│`);
|
|
62
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
63
|
+
console.log(`│ Available modes: │`);
|
|
64
|
+
|
|
65
|
+
for (const mode of VALID_MODES) {
|
|
66
|
+
const marker = mode === currentMode ? '●' : '○';
|
|
67
|
+
const info = MODE_INFO[mode];
|
|
68
|
+
console.log(`│ ${marker} ${mode.padEnd(12)} ${info.description.substring(0, 26).padEnd(26)}│`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
72
|
+
console.log(`│ Usage: /plexor-mode <mode> │`);
|
|
73
|
+
console.log(`│ Example: /plexor-mode eco │`);
|
|
74
|
+
console.log(`└─────────────────────────────────────────────┘`);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const newMode = args[0].toLowerCase();
|
|
79
|
+
|
|
80
|
+
if (!VALID_MODES.includes(newMode)) {
|
|
81
|
+
console.error(`Error: Invalid mode "${newMode}"`);
|
|
82
|
+
console.error(`Valid modes: ${VALID_MODES.join(', ')}`);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (newMode === currentMode) {
|
|
87
|
+
console.log(`Mode is already set to "${currentMode}"`);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
config.settings = config.settings || {};
|
|
92
|
+
config.settings.mode = newMode;
|
|
93
|
+
saveConfig(config);
|
|
94
|
+
|
|
95
|
+
const info = MODE_INFO[newMode];
|
|
96
|
+
console.log(`┌─────────────────────────────────────────────┐`);
|
|
97
|
+
console.log(`│ ✓ Mode Updated │`);
|
|
98
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
99
|
+
console.log(`│ Previous: ${currentMode.padEnd(32)}│`);
|
|
100
|
+
console.log(`│ New: ${newMode.padEnd(37)}│`);
|
|
101
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
102
|
+
console.log(`│ ${info.description.padEnd(42)}│`);
|
|
103
|
+
console.log(`│ Models: ${info.models.substring(0, 34).padEnd(34)}│`);
|
|
104
|
+
console.log(`└─────────────────────────────────────────────┘`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
main();
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Plexor Provider Command
|
|
5
|
+
* Force a specific LLM provider
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
const CONFIG_PATH = path.join(process.env.HOME, '.plexor', 'config.json');
|
|
12
|
+
const PLEXOR_DIR = path.join(process.env.HOME, '.plexor');
|
|
13
|
+
|
|
14
|
+
const VALID_PROVIDERS = ['auto', 'claude', 'anthropic', 'openai', 'deepseek', 'mistral', 'gemini', 'google'];
|
|
15
|
+
|
|
16
|
+
const PROVIDER_INFO = {
|
|
17
|
+
auto: 'Automatic routing based on task and mode',
|
|
18
|
+
claude: 'Anthropic Claude models (alias for anthropic)',
|
|
19
|
+
anthropic: 'Anthropic Claude models',
|
|
20
|
+
openai: 'OpenAI GPT models',
|
|
21
|
+
deepseek: 'DeepSeek models (excellent for code)',
|
|
22
|
+
mistral: 'Mistral AI models',
|
|
23
|
+
gemini: 'Google Gemini models',
|
|
24
|
+
google: 'Google Gemini models (alias for gemini)'
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function loadConfig() {
|
|
28
|
+
try {
|
|
29
|
+
const data = fs.readFileSync(CONFIG_PATH, 'utf8');
|
|
30
|
+
return JSON.parse(data);
|
|
31
|
+
} catch {
|
|
32
|
+
return { version: 1, auth: {}, settings: {} };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function saveConfig(config) {
|
|
37
|
+
if (!fs.existsSync(PLEXOR_DIR)) {
|
|
38
|
+
fs.mkdirSync(PLEXOR_DIR, { recursive: true, mode: 0o700 });
|
|
39
|
+
}
|
|
40
|
+
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function normalizeProvider(provider) {
|
|
44
|
+
const normalized = provider.toLowerCase();
|
|
45
|
+
if (normalized === 'claude') return 'anthropic';
|
|
46
|
+
if (normalized === 'google') return 'gemini';
|
|
47
|
+
return normalized;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function main() {
|
|
51
|
+
const args = process.argv.slice(2);
|
|
52
|
+
const config = loadConfig();
|
|
53
|
+
const currentProvider = config.settings?.preferred_provider || 'auto';
|
|
54
|
+
|
|
55
|
+
// No args - show current provider and options
|
|
56
|
+
if (args.length === 0) {
|
|
57
|
+
console.log(`┌─────────────────────────────────────────────┐`);
|
|
58
|
+
console.log(`│ Plexor Provider Routing │`);
|
|
59
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
60
|
+
console.log(`│ Current: ${currentProvider.padEnd(33)}│`);
|
|
61
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
62
|
+
console.log(`│ Available providers: │`);
|
|
63
|
+
|
|
64
|
+
const displayProviders = ['auto', 'anthropic', 'openai', 'deepseek', 'mistral', 'gemini'];
|
|
65
|
+
for (const provider of displayProviders) {
|
|
66
|
+
const marker = provider === currentProvider ? '●' : '○';
|
|
67
|
+
const info = PROVIDER_INFO[provider];
|
|
68
|
+
console.log(`│ ${marker} ${provider.padEnd(10)} ${info.substring(0, 29).padEnd(29)}│`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
72
|
+
console.log(`│ Usage: /plexor-provider <provider> │`);
|
|
73
|
+
console.log(`│ Example: /plexor-provider deepseek │`);
|
|
74
|
+
console.log(`│ Aliases: claude→anthropic, google→gemini │`);
|
|
75
|
+
console.log(`└─────────────────────────────────────────────┘`);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const inputProvider = args[0].toLowerCase();
|
|
80
|
+
|
|
81
|
+
if (!VALID_PROVIDERS.includes(inputProvider)) {
|
|
82
|
+
console.error(`Error: Invalid provider "${args[0]}"`);
|
|
83
|
+
console.error(`Valid providers: auto, anthropic, openai, deepseek, mistral, gemini`);
|
|
84
|
+
console.error(`Aliases: claude (→anthropic), google (→gemini)`);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const newProvider = normalizeProvider(inputProvider);
|
|
89
|
+
|
|
90
|
+
if (newProvider === currentProvider) {
|
|
91
|
+
console.log(`Provider is already set to "${currentProvider}"`);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
config.settings = config.settings || {};
|
|
96
|
+
config.settings.preferred_provider = newProvider;
|
|
97
|
+
saveConfig(config);
|
|
98
|
+
|
|
99
|
+
const info = PROVIDER_INFO[newProvider];
|
|
100
|
+
console.log(`┌─────────────────────────────────────────────┐`);
|
|
101
|
+
console.log(`│ ✓ Provider Updated │`);
|
|
102
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
103
|
+
console.log(`│ Previous: ${currentProvider.padEnd(32)}│`);
|
|
104
|
+
console.log(`│ New: ${newProvider.padEnd(37)}│`);
|
|
105
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
106
|
+
console.log(`│ ${info.padEnd(42)}│`);
|
|
107
|
+
console.log(`└─────────────────────────────────────────────┘`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
main();
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Plexor Settings Command
|
|
5
|
+
* View and update Plexor configuration settings
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
const CONFIG_PATH = path.join(process.env.HOME, '.plexor', 'config.json');
|
|
12
|
+
const PLEXOR_DIR = path.join(process.env.HOME, '.plexor');
|
|
13
|
+
|
|
14
|
+
const SETTING_KEYS = {
|
|
15
|
+
'api-url': 'apiUrl',
|
|
16
|
+
'apiurl': 'apiUrl',
|
|
17
|
+
'url': 'apiUrl',
|
|
18
|
+
'timeout': 'timeout',
|
|
19
|
+
'cache': 'localCacheEnabled',
|
|
20
|
+
'local-cache': 'localCacheEnabled'
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function loadConfig() {
|
|
24
|
+
try {
|
|
25
|
+
const data = fs.readFileSync(CONFIG_PATH, 'utf8');
|
|
26
|
+
return JSON.parse(data);
|
|
27
|
+
} catch {
|
|
28
|
+
return { version: 1, auth: {}, settings: {} };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function saveConfig(config) {
|
|
33
|
+
if (!fs.existsSync(PLEXOR_DIR)) {
|
|
34
|
+
fs.mkdirSync(PLEXOR_DIR, { recursive: true, mode: 0o700 });
|
|
35
|
+
}
|
|
36
|
+
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function parseValue(key, value) {
|
|
40
|
+
const normalizedKey = SETTING_KEYS[key.toLowerCase()] || key;
|
|
41
|
+
|
|
42
|
+
switch (normalizedKey) {
|
|
43
|
+
case 'localCacheEnabled':
|
|
44
|
+
return ['true', 'on', 'yes', '1'].includes(value.toLowerCase());
|
|
45
|
+
case 'timeout':
|
|
46
|
+
const num = parseInt(value, 10);
|
|
47
|
+
if (isNaN(num) || num < 1000 || num > 60000) {
|
|
48
|
+
throw new Error('Timeout must be between 1000-60000ms');
|
|
49
|
+
}
|
|
50
|
+
return num;
|
|
51
|
+
case 'apiUrl':
|
|
52
|
+
if (!value.startsWith('http://') && !value.startsWith('https://')) {
|
|
53
|
+
throw new Error('API URL must start with http:// or https://');
|
|
54
|
+
}
|
|
55
|
+
return value;
|
|
56
|
+
default:
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function main() {
|
|
62
|
+
const args = process.argv.slice(2);
|
|
63
|
+
const config = loadConfig();
|
|
64
|
+
const settings = config.settings || {};
|
|
65
|
+
|
|
66
|
+
// No args - show current settings
|
|
67
|
+
if (args.length === 0) {
|
|
68
|
+
const enabled = settings.enabled ?? false;
|
|
69
|
+
const mode = settings.mode || 'balanced';
|
|
70
|
+
const provider = settings.preferred_provider || 'auto';
|
|
71
|
+
const apiUrl = settings.apiUrl || 'https://api.plexor.dev';
|
|
72
|
+
const timeout = settings.timeout || 5000;
|
|
73
|
+
const cache = settings.localCacheEnabled ?? false;
|
|
74
|
+
const hasApiKey = !!config.auth?.api_key;
|
|
75
|
+
|
|
76
|
+
console.log(`┌─────────────────────────────────────────────┐`);
|
|
77
|
+
console.log(`│ Plexor Settings │`);
|
|
78
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
79
|
+
console.log(`│ Authentication │`);
|
|
80
|
+
console.log(`│ └── API Key: ${(hasApiKey ? 'Configured' : 'Not set').padEnd(29)}│`);
|
|
81
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
82
|
+
console.log(`│ Proxy │`);
|
|
83
|
+
console.log(`│ ├── Enabled: ${(enabled ? 'Yes' : 'No').padEnd(29)}│`);
|
|
84
|
+
console.log(`│ └── API URL: ${apiUrl.substring(0, 29).padEnd(29)}│`);
|
|
85
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
86
|
+
console.log(`│ Optimization │`);
|
|
87
|
+
console.log(`│ ├── Mode: ${mode.padEnd(32)}│`);
|
|
88
|
+
console.log(`│ └── Provider: ${provider.padEnd(27)}│`);
|
|
89
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
90
|
+
console.log(`│ Performance │`);
|
|
91
|
+
console.log(`│ ├── Local Cache: ${(cache ? 'Enabled' : 'Disabled').padEnd(24)}│`);
|
|
92
|
+
console.log(`│ └── Timeout: ${(timeout + 'ms').padEnd(29)}│`);
|
|
93
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
94
|
+
console.log(`│ Modify settings: │`);
|
|
95
|
+
console.log(`│ /plexor-settings <key> <value> │`);
|
|
96
|
+
console.log(`│ │`);
|
|
97
|
+
console.log(`│ Available keys: │`);
|
|
98
|
+
console.log(`│ api-url, timeout, cache │`);
|
|
99
|
+
console.log(`│ │`);
|
|
100
|
+
console.log(`│ Other commands: │`);
|
|
101
|
+
console.log(`│ /plexor-mode - Set optimization mode │`);
|
|
102
|
+
console.log(`│ /plexor-provider - Set provider routing │`);
|
|
103
|
+
console.log(`│ /plexor-enabled - Enable/disable proxy │`);
|
|
104
|
+
console.log(`└─────────────────────────────────────────────┘`);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Get setting
|
|
109
|
+
if (args.length === 1) {
|
|
110
|
+
const key = args[0].toLowerCase();
|
|
111
|
+
const normalizedKey = SETTING_KEYS[key] || key;
|
|
112
|
+
const value = settings[normalizedKey];
|
|
113
|
+
|
|
114
|
+
if (value === undefined) {
|
|
115
|
+
console.error(`Unknown setting: ${args[0]}`);
|
|
116
|
+
console.error(`Available: api-url, timeout, cache`);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
console.log(`${normalizedKey}: ${value}`);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Set setting
|
|
125
|
+
const key = args[0].toLowerCase();
|
|
126
|
+
const normalizedKey = SETTING_KEYS[key];
|
|
127
|
+
|
|
128
|
+
if (!normalizedKey) {
|
|
129
|
+
console.error(`Unknown setting: ${args[0]}`);
|
|
130
|
+
console.error(`Available: api-url, timeout, cache`);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
const value = parseValue(key, args[1]);
|
|
136
|
+
const oldValue = settings[normalizedKey];
|
|
137
|
+
|
|
138
|
+
config.settings = config.settings || {};
|
|
139
|
+
config.settings[normalizedKey] = value;
|
|
140
|
+
saveConfig(config);
|
|
141
|
+
|
|
142
|
+
console.log(`┌─────────────────────────────────────────────┐`);
|
|
143
|
+
console.log(`│ ✓ Setting Updated │`);
|
|
144
|
+
console.log(`├─────────────────────────────────────────────┤`);
|
|
145
|
+
console.log(`│ Key: ${normalizedKey.padEnd(37)}│`);
|
|
146
|
+
console.log(`│ Previous: ${String(oldValue ?? 'not set').substring(0, 32).padEnd(32)}│`);
|
|
147
|
+
console.log(`│ New: ${String(value).substring(0, 37).padEnd(37)}│`);
|
|
148
|
+
console.log(`└─────────────────────────────────────────────┘`);
|
|
149
|
+
} catch (err) {
|
|
150
|
+
console.error(`Error: ${err.message}`);
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
main();
|
|
File without changes
|
package/lib/plexor-client.js
CHANGED
|
@@ -31,7 +31,7 @@ class PlexorClient {
|
|
|
31
31
|
'Content-Type': 'application/json',
|
|
32
32
|
'X-API-Key': this.apiKey,
|
|
33
33
|
'X-Plexor-Key': this.apiKey,
|
|
34
|
-
'User-Agent': 'plexor-claude-code-plugin/0.1.0'
|
|
34
|
+
'User-Agent': 'plexor-claude-code-plugin/0.1.0-beta.21'
|
|
35
35
|
},
|
|
36
36
|
timeout: this.timeout
|
|
37
37
|
};
|
package/package.json
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plexor-dev/claude-code-plugin",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.21",
|
|
4
4
|
"description": "LLM cost optimization plugin for Claude Code - Save up to 90% on AI costs",
|
|
5
5
|
"main": "lib/constants.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"plexor-status": "./commands/plexor-status.js",
|
|
8
|
+
"plexor-mode": "./commands/plexor-mode.js",
|
|
9
|
+
"plexor-enabled": "./commands/plexor-enabled.js",
|
|
10
|
+
"plexor-provider": "./commands/plexor-provider.js",
|
|
11
|
+
"plexor-login": "./commands/plexor-login.js",
|
|
12
|
+
"plexor-logout": "./commands/plexor-logout.js",
|
|
13
|
+
"plexor-settings": "./commands/plexor-settings.js",
|
|
14
|
+
"plexor-config": "./commands/plexor-config.js"
|
|
15
|
+
},
|
|
6
16
|
"scripts": {
|
|
7
17
|
"postinstall": "node scripts/postinstall.js",
|
|
8
18
|
"preuninstall": "node scripts/uninstall.js",
|