@plexor-dev/claude-code-plugin 0.1.0-beta.20 → 0.1.0-beta.22

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.
@@ -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();
@@ -4,41 +4,24 @@ description: Log out from Plexor and clear credentials (user)
4
4
 
5
5
  # Plexor Logout
6
6
 
7
- Log out from your Plexor account and clear stored credentials.
7
+ Run this command to log out and clear credentials:
8
8
 
9
- ## Steps
10
-
11
- **Step 1: Read current configuration**
12
-
13
- Use the Read tool to read `~/.plexor/config.json`.
14
-
15
- If the file doesn't exist or has no `apiKey`, show:
16
- ```
17
- Plexor Logout
18
- =============
19
- You are not currently logged in.
20
- Run /plexor-login to authenticate.
9
+ ```bash
10
+ node ~/.claude/plugins/plexor/commands/plexor-logout.js
21
11
  ```
22
12
 
23
- **Step 2: Clear the API key**
24
-
25
- If authenticated, use the Write tool to update `~/.plexor/config.json`:
26
- - Remove or clear the `apiKey` field (set to empty string "")
27
- - Keep all other settings (mode, preferredProvider, etc.)
28
-
29
- **Step 3: Show confirmation**
13
+ To also clear the cache:
30
14
 
15
+ ```bash
16
+ node ~/.claude/plugins/plexor/commands/plexor-logout.js --clear-cache
31
17
  ```
32
- Plexor Logout
33
- =============
34
- Successfully logged out!
35
18
 
36
- - API key cleared from ~/.plexor/config.json
37
- - Settings preserved (mode, provider preferences)
19
+ Use the Bash tool to execute this command.
38
20
 
39
- To use Plexor again, run /plexor-login
40
-
41
- Dashboard: https://plexor.dev/dashboard
42
- ```
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
43
26
 
44
- **IMPORTANT**: After completing the task, STOP. Do not run additional commands or explore the codebase.
27
+ The command output is the complete response. Simply show the output and wait for the user's next input.
@@ -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();
@@ -4,46 +4,24 @@ description: Set Plexor optimization mode (eco/balanced/quality/passthrough) (us
4
4
 
5
5
  # Plexor Mode
6
6
 
7
- Set the Plexor optimization mode to control cost vs quality trade-offs.
7
+ Run this command to view or set the optimization mode:
8
8
 
9
- ## Steps
10
-
11
- **Step 1: Read current configuration**
12
-
13
- Use the Read tool to read `~/.plexor/config.json` and check the current `mode` setting.
14
-
15
- **Step 2: Ask user which mode they want**
16
-
17
- Use the `AskUserQuestion` tool:
18
-
19
- Question: "Which optimization mode would you like to use?"
20
- Header: "Mode"
21
- Options:
22
- 1. **eco** - Maximum savings (~$0.04/1M tokens) - Uses Ministral 3B
23
- 2. **balanced** - Good balance (~$0.15/1M) - DeepSeek, Gemini Flash, Mistral Small
24
- 3. **quality** - Premium models (~$5/1M) - Claude Opus, Gemini Pro, Mistral Large
25
- 4. **passthrough** - No optimization - Direct to requested model
26
-
27
- **Step 3: Update the configuration**
28
-
29
- Use the Read tool to get the current config, then use the Write tool to update `~/.plexor/config.json`:
30
- - Set the `mode` field to the selected value: "eco", "balanced", "quality", or "passthrough"
31
-
32
- Keep all other settings unchanged.
9
+ ```bash
10
+ node ~/.claude/plugins/plexor/commands/plexor-mode.js
11
+ ```
33
12
 
34
- **Step 4: Show confirmation**
13
+ To set a specific mode, pass it as an argument:
35
14
 
15
+ ```bash
16
+ node ~/.claude/plugins/plexor/commands/plexor-mode.js balanced
36
17
  ```
37
- Plexor Mode: [SELECTED MODE]
38
18
 
39
- Mode Details:
40
- - eco: Maximum cost savings using Ministral 3B ($0.04/$0.04 per 1M tokens)
41
- - balanced: Cost-first with quality fallbacks (DeepSeek → Gemini Flash → Mistral)
42
- - quality: Premium models for complex tasks (Claude Opus, Gemini Pro)
43
- - passthrough: No optimization, direct to Anthropic
19
+ Use the Bash tool to execute this command.
44
20
 
45
- Current mode: [mode]
46
- Run /plexor-status to see your savings.
47
- ```
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
48
26
 
49
- **IMPORTANT**: After completing the task, STOP. Do not run additional commands or explore the codebase.
27
+ The command output is the complete response. Simply show the output and wait for the user's next input.
@@ -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();
@@ -4,46 +4,24 @@ description: Force a specific LLM provider (claude/openai/deepseek/mistral/gemin
4
4
 
5
5
  # Plexor Provider
6
6
 
7
- Set your preferred LLM provider for Plexor routing.
7
+ Run this command to view or set the preferred provider:
8
8
 
9
- ## Steps
10
-
11
- **Step 1: Read current configuration**
12
-
13
- Use the Read tool to read `~/.plexor/config.json` and check the current `preferredProvider` setting.
14
-
15
- **Step 2: Ask user which provider they prefer**
16
-
17
- Use the `AskUserQuestion` tool:
18
-
19
- Question: "Which LLM provider would you prefer?"
20
- Header: "Provider"
21
- Options:
22
- 1. **auto** - Let Plexor choose the best provider based on task (Recommended)
23
- 2. **deepseek** - Use DeepSeek models (cheapest, good for code)
24
- 3. **mistral** - Use Mistral models (fast, good balance)
25
- 4. **gemini** - Use Google Gemini models (good for analysis)
26
-
27
- **Step 3: Update the configuration**
28
-
29
- Use the Read tool to get the current config, then use the Write tool to update `~/.plexor/config.json`:
30
- - Set `preferredProvider` to: "auto", "deepseek", "mistral", or "gemini"
31
-
32
- Keep all other settings unchanged.
9
+ ```bash
10
+ node ~/.claude/plugins/plexor/commands/plexor-provider.js
11
+ ```
33
12
 
34
- **Step 4: Show confirmation**
13
+ To set a specific provider:
35
14
 
15
+ ```bash
16
+ node ~/.claude/plugins/plexor/commands/plexor-provider.js deepseek
36
17
  ```
37
- Plexor Provider: [SELECTED PROVIDER]
38
18
 
39
- Provider options:
40
- - auto: Plexor automatically selects the best provider for each task
41
- - deepseek: DeepSeek models ($0.14/$0.28 per 1M tokens) - Great for code
42
- - mistral: Mistral models ($0.10/$0.30 per 1M tokens) - Fast and versatile
43
- - gemini: Google Gemini ($0.075/$0.30 per 1M tokens) - Good for analysis
19
+ Use the Bash tool to execute this command.
44
20
 
45
- Current provider: [preferredProvider]
46
- Run /plexor-status to see your usage.
47
- ```
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
48
26
 
49
- **IMPORTANT**: After completing the task, STOP. Do not run additional commands or explore the codebase.
27
+ The command output is the complete response. Simply show the output and wait for the user's next input.
@@ -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();