@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,110 +1,91 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Plexor Provider
|
|
5
|
-
*
|
|
4
|
+
* Plexor Provider — select which LLM provider to use.
|
|
5
|
+
*
|
|
6
|
+
* Provider options:
|
|
7
|
+
* auto: Best model for task (router decides, default)
|
|
8
|
+
* anthropic: Claude (Anthropic)
|
|
9
|
+
* openai: GPT (OpenAI)
|
|
10
|
+
* deepseek: DeepSeek
|
|
11
|
+
* mistral: Mistral
|
|
12
|
+
* gemini: Gemini (Google)
|
|
13
|
+
* grok: Grok (xAI)
|
|
14
|
+
* cohere: Command-R (Cohere)
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* /plexor-provider Show current provider
|
|
18
|
+
* /plexor-provider auto Let router decide (default)
|
|
19
|
+
* /plexor-provider anthropic Force Claude
|
|
20
|
+
* /plexor-provider openai Force GPT
|
|
6
21
|
*/
|
|
7
22
|
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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)'
|
|
23
|
+
const { loadConfig, saveConfig, readSetting } = require('../lib/config-utils');
|
|
24
|
+
|
|
25
|
+
const VALID = ['auto', 'anthropic', 'openai', 'deepseek', 'mistral', 'gemini', 'grok', 'cohere'];
|
|
26
|
+
const DESC = {
|
|
27
|
+
auto: 'Best model for task (router decides)',
|
|
28
|
+
anthropic: 'Claude (Anthropic)',
|
|
29
|
+
openai: 'GPT (OpenAI)',
|
|
30
|
+
deepseek: 'DeepSeek',
|
|
31
|
+
mistral: 'Mistral',
|
|
32
|
+
gemini: 'Gemini (Google)',
|
|
33
|
+
grok: 'Grok (xAI)',
|
|
34
|
+
cohere: 'Command-R (Cohere)'
|
|
25
35
|
};
|
|
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
|
-
}
|
|
36
|
+
const ALIASES = { claude: 'anthropic' };
|
|
49
37
|
|
|
50
38
|
function main() {
|
|
51
39
|
const args = process.argv.slice(2);
|
|
52
40
|
const config = loadConfig();
|
|
53
|
-
const
|
|
41
|
+
const current = readSetting(config, 'preferred_provider', null, 'PLEXOR_PROVIDER', VALID, 'auto');
|
|
54
42
|
|
|
55
|
-
// No args - show current provider and options
|
|
56
43
|
if (args.length === 0) {
|
|
57
|
-
console.log(
|
|
58
|
-
console.log(
|
|
59
|
-
console.log(
|
|
60
|
-
console.log(
|
|
61
|
-
|
|
62
|
-
|
|
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)}│`);
|
|
44
|
+
console.log(`Provider: ${current.value} (${current.source})`);
|
|
45
|
+
console.log(` ${DESC[current.value]}`);
|
|
46
|
+
console.log('');
|
|
47
|
+
console.log('Options:');
|
|
48
|
+
for (const v of VALID) {
|
|
49
|
+
const marker = v === current.value ? '>>' : ' ';
|
|
50
|
+
console.log(` ${marker} ${v.padEnd(12)} ${DESC[v]}`);
|
|
69
51
|
}
|
|
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(`└─────────────────────────────────────────────┘`);
|
|
52
|
+
console.log('');
|
|
53
|
+
console.log('Set: /plexor-provider <name>');
|
|
76
54
|
return;
|
|
77
55
|
}
|
|
78
56
|
|
|
79
|
-
|
|
57
|
+
let requested = args[0].toLowerCase().trim();
|
|
58
|
+
if (ALIASES[requested]) requested = ALIASES[requested];
|
|
80
59
|
|
|
81
|
-
if (!
|
|
82
|
-
console.error(`
|
|
83
|
-
console.error(`Valid
|
|
84
|
-
console.error(`Aliases: claude (→anthropic), google (→gemini)`);
|
|
60
|
+
if (!VALID.includes(requested)) {
|
|
61
|
+
console.error(`Invalid provider: "${args[0]}"`);
|
|
62
|
+
console.error(`Valid: ${VALID.join(', ')}`);
|
|
85
63
|
process.exit(1);
|
|
86
64
|
}
|
|
87
65
|
|
|
88
|
-
|
|
66
|
+
if (current.source === 'environment' && requested !== current.value) {
|
|
67
|
+
console.log(`Warning: PLEXOR_PROVIDER env var is set to "${current.value}". Config updated but env var takes priority.`);
|
|
68
|
+
}
|
|
89
69
|
|
|
90
|
-
if (
|
|
91
|
-
console.log(`
|
|
70
|
+
if (requested === current.value && current.source === 'config') {
|
|
71
|
+
console.log(`Already set to "${requested}".`);
|
|
92
72
|
return;
|
|
93
73
|
}
|
|
94
74
|
|
|
95
75
|
config.settings = config.settings || {};
|
|
96
|
-
config.settings.preferred_provider =
|
|
97
|
-
|
|
76
|
+
config.settings.preferred_provider = requested;
|
|
77
|
+
if (requested !== 'auto') {
|
|
78
|
+
delete config.settings.preferred_model;
|
|
79
|
+
delete config.settings.preferredModel;
|
|
80
|
+
}
|
|
81
|
+
if (!saveConfig(config)) { process.exit(1); }
|
|
98
82
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
console.log(
|
|
104
|
-
console.log(
|
|
105
|
-
console.log(`├─────────────────────────────────────────────┤`);
|
|
106
|
-
console.log(`│ ${info.padEnd(42)}│`);
|
|
107
|
-
console.log(`└─────────────────────────────────────────────┘`);
|
|
83
|
+
console.log(`Provider: ${current.value} → ${requested}`);
|
|
84
|
+
if (requested !== 'auto') {
|
|
85
|
+
console.log(' Cleared preferred_model to keep provider/model force hints mutually exclusive.');
|
|
86
|
+
}
|
|
87
|
+
console.log(` ${DESC[requested]}`);
|
|
88
|
+
console.log(' Takes effect on next request.');
|
|
108
89
|
}
|
|
109
90
|
|
|
110
91
|
main();
|
|
@@ -1,27 +1,37 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: Set Plexor LLM provider — auto, anthropic, openai, deepseek, gemini, etc. (user)
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Step 1: Check if arguments were provided.**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
If `$ARGUMENTS` contains a value (e.g., `/plexor-provider anthropic`), apply it directly:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
node ~/.claude/plugins/plexor/commands/plexor-provider.js
|
|
10
|
+
node ~/.claude/plugins/plexor/commands/plexor-provider.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 NO arguments were provided** (just `/plexor-provider`), first show the current state:
|
|
14
16
|
|
|
15
17
|
```bash
|
|
16
|
-
node ~/.claude/plugins/plexor/commands/plexor-provider.js
|
|
18
|
+
node ~/.claude/plugins/plexor/commands/plexor-provider.js
|
|
17
19
|
```
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
Then immediately use **AskUserQuestion** to let the user pick a provider:
|
|
22
|
+
|
|
23
|
+
- **Question**: "Which LLM provider?"
|
|
24
|
+
- **Header**: "Provider"
|
|
25
|
+
- **Options** (exactly 4 — "Other" auto-covers mistral, gemini, grok, cohere):
|
|
26
|
+
1. **auto (Recommended)** — "Let Plexor choose the best provider automatically"
|
|
27
|
+
2. **anthropic** — "Claude models (Opus, Sonnet, Haiku)"
|
|
28
|
+
3. **openai** — "GPT models (GPT-4o, GPT-4.1, o1)"
|
|
29
|
+
4. **deepseek** — "DeepSeek models (Chat, Reasoner)"
|
|
20
30
|
|
|
21
|
-
**
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
-
|
|
25
|
-
|
|
31
|
+
**Step 3: After the user selects**, apply their choice. If the user picks "Other", they will type the provider name (mistral, gemini, grok, cohere):
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
node ~/.claude/plugins/plexor/commands/plexor-provider.js <selected_value>
|
|
35
|
+
```
|
|
26
36
|
|
|
27
|
-
|
|
37
|
+
Present the output and STOP. Do NOT re-execute commands or call other tools.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Plexor Routing — set the cost/quality routing mode.
|
|
5
|
+
*
|
|
6
|
+
* Routing modes control how aggressively Plexor optimizes for cost:
|
|
7
|
+
* eco: 60-90% savings, cheapest models
|
|
8
|
+
* balanced: 40-60% savings, good balance (default)
|
|
9
|
+
* quality: 20-40% savings, premium models
|
|
10
|
+
* passthrough: No optimization, direct to provider
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* /plexor-routing Show current routing mode
|
|
14
|
+
* /plexor-routing eco Set to eco (maximum savings)
|
|
15
|
+
* /plexor-routing balanced Set to balanced
|
|
16
|
+
* /plexor-routing quality Set to quality
|
|
17
|
+
* /plexor-routing passthrough Set to passthrough (no optimization)
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const { loadConfig, saveConfig, readSetting } = require('../lib/config-utils');
|
|
21
|
+
|
|
22
|
+
const VALID = ['eco', 'balanced', 'quality', 'passthrough'];
|
|
23
|
+
const DESC = {
|
|
24
|
+
eco: '60-90% savings, cheapest models',
|
|
25
|
+
balanced: '40-60% savings, good balance',
|
|
26
|
+
quality: '20-40% savings, premium models',
|
|
27
|
+
passthrough: 'No optimization, direct to provider'
|
|
28
|
+
};
|
|
29
|
+
const ALIASES = { cost: 'eco' };
|
|
30
|
+
|
|
31
|
+
function main() {
|
|
32
|
+
const args = process.argv.slice(2);
|
|
33
|
+
const config = loadConfig();
|
|
34
|
+
const current = readSetting(config, 'mode', null, 'PLEXOR_MODE', VALID, 'balanced');
|
|
35
|
+
|
|
36
|
+
if (args.length === 0) {
|
|
37
|
+
console.log(`Routing Mode: ${current.value} (${current.source})`);
|
|
38
|
+
console.log(` ${DESC[current.value]}`);
|
|
39
|
+
console.log('');
|
|
40
|
+
console.log('Options:');
|
|
41
|
+
for (const v of VALID) {
|
|
42
|
+
const marker = v === current.value ? '>>' : ' ';
|
|
43
|
+
console.log(` ${marker} ${v.padEnd(14)} ${DESC[v]}`);
|
|
44
|
+
}
|
|
45
|
+
console.log('');
|
|
46
|
+
console.log('Set: /plexor-routing <mode>');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let requested = args[0].toLowerCase().trim();
|
|
51
|
+
if (ALIASES[requested]) requested = ALIASES[requested];
|
|
52
|
+
|
|
53
|
+
if (!VALID.includes(requested)) {
|
|
54
|
+
console.error(`Invalid routing mode: "${args[0]}"`);
|
|
55
|
+
console.error(`Valid: ${VALID.join(', ')}`);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (current.source === 'environment' && requested !== current.value) {
|
|
60
|
+
console.log(`Warning: PLEXOR_MODE env var is set to "${current.value}". Config updated but env var takes priority.`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (requested === current.value && current.source === 'config') {
|
|
64
|
+
console.log(`Already set to "${requested}".`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
config.settings = config.settings || {};
|
|
69
|
+
config.settings.mode = requested;
|
|
70
|
+
if (!saveConfig(config)) { process.exit(1); }
|
|
71
|
+
|
|
72
|
+
console.log(`Routing mode: ${current.value} → ${requested}`);
|
|
73
|
+
console.log(` ${DESC[requested]}`);
|
|
74
|
+
console.log(' Takes effect on next request.');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
main();
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Set Plexor routing mode — eco, balanced, quality, or passthrough (user)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
**Step 1: Check if arguments were provided.**
|
|
6
|
+
|
|
7
|
+
If `$ARGUMENTS` contains a value (e.g., `/plexor-routing eco`), apply it directly:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
node ~/.claude/plugins/plexor/commands/plexor-routing.js $ARGUMENTS
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Present the output to the user and STOP. Do NOT call any other tools.
|
|
14
|
+
|
|
15
|
+
**Step 2: If NO arguments were provided** (just `/plexor-routing`), first show the current state:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
node ~/.claude/plugins/plexor/commands/plexor-routing.js
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Then immediately use **AskUserQuestion** to let the user pick a mode:
|
|
22
|
+
|
|
23
|
+
- **Question**: "Which routing mode?"
|
|
24
|
+
- **Header**: "Routing"
|
|
25
|
+
- **Options** (exactly 4):
|
|
26
|
+
1. **eco (Recommended)** — "Cheapest models first, best cost efficiency"
|
|
27
|
+
2. **balanced** — "Balance cost and quality, smart model selection"
|
|
28
|
+
3. **quality** — "Premium models, best output quality"
|
|
29
|
+
4. **passthrough** — "Direct provider access, no routing logic"
|
|
30
|
+
|
|
31
|
+
**Step 3: After the user selects**, apply their choice:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
node ~/.claude/plugins/plexor/commands/plexor-routing.js <selected_value>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Present the output and STOP. Do NOT re-execute commands or call other tools.
|
|
@@ -1,155 +1,193 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Plexor Settings
|
|
5
|
-
*
|
|
4
|
+
* Plexor Settings — unified dashboard for all Plexor configuration.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* /plexor-settings Show all settings
|
|
8
|
+
* /plexor-settings routing <value> Set routing mode
|
|
9
|
+
* /plexor-settings agent <value> Set agent autonomy
|
|
10
|
+
* /plexor-settings provider <value> Set LLM provider
|
|
6
11
|
*/
|
|
7
12
|
|
|
8
|
-
const
|
|
9
|
-
const path = require('path');
|
|
13
|
+
const { loadConfig, saveConfig, readSetting } = require('../lib/config-utils');
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
const PLEXOR_DIR = path.join(process.env.HOME, '.plexor');
|
|
15
|
+
// ── Definitions ──────────────────────────────────────────────────────────────
|
|
13
16
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
'
|
|
17
|
-
'
|
|
18
|
-
'
|
|
19
|
-
|
|
20
|
-
'local-cache': 'localCacheEnabled'
|
|
17
|
+
const ROUTING_MODES = ['eco', 'balanced', 'quality', 'passthrough'];
|
|
18
|
+
const ROUTING_DESC = {
|
|
19
|
+
eco: '60-90% savings, cheapest models',
|
|
20
|
+
balanced: '40-60% savings, good balance',
|
|
21
|
+
quality: '20-40% savings, premium models',
|
|
22
|
+
passthrough: 'No optimization, direct to provider'
|
|
21
23
|
};
|
|
24
|
+
const ROUTING_ALIASES = { cost: 'eco' };
|
|
22
25
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
const AGENT_MODES = ['supervised', 'autonomous', 'danger-full-auto'];
|
|
27
|
+
const AGENT_DESC = {
|
|
28
|
+
supervised: 'Confirm before acting',
|
|
29
|
+
autonomous: 'Acts within safe bounds',
|
|
30
|
+
'danger-full-auto': 'Full autonomy, no guardrails'
|
|
31
|
+
};
|
|
32
|
+
const AGENT_ALIASES = { auto: 'autonomous', fullauto: 'danger-full-auto', 'full-auto': 'danger-full-auto', full_auto: 'danger-full-auto' };
|
|
33
|
+
|
|
34
|
+
const PROVIDERS = ['auto', 'anthropic', 'openai', 'deepseek', 'mistral', 'gemini', 'grok', 'cohere'];
|
|
35
|
+
const PROVIDER_DESC = {
|
|
36
|
+
auto: 'Best model for task (router decides)',
|
|
37
|
+
anthropic: 'Claude (Anthropic)',
|
|
38
|
+
openai: 'GPT (OpenAI)',
|
|
39
|
+
deepseek: 'DeepSeek',
|
|
40
|
+
mistral: 'Mistral',
|
|
41
|
+
gemini: 'Gemini (Google)',
|
|
42
|
+
grok: 'Grok (xAI)',
|
|
43
|
+
cohere: 'Command-R (Cohere)'
|
|
44
|
+
};
|
|
45
|
+
const PROVIDER_ALIASES = { claude: 'anthropic' };
|
|
46
|
+
|
|
47
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
48
|
+
|
|
49
|
+
function pad(s, n) { return String(s).padEnd(n); }
|
|
50
|
+
|
|
51
|
+
function showDashboard(config) {
|
|
52
|
+
const routing = readSetting(config, 'mode', null, 'PLEXOR_MODE', ROUTING_MODES, 'balanced');
|
|
53
|
+
const agent = readSetting(config, 'orchestrationMode', 'orchestration_mode', 'PLEXOR_ORCHESTRATION_MODE', AGENT_MODES, 'autonomous');
|
|
54
|
+
const provider = readSetting(config, 'preferred_provider', null, 'PLEXOR_PROVIDER', PROVIDERS, 'auto');
|
|
55
|
+
|
|
56
|
+
const W = 56;
|
|
57
|
+
const line = '─'.repeat(W - 2);
|
|
58
|
+
const row = (label, val, desc, src) => {
|
|
59
|
+
const marker = `${val} (${src})`;
|
|
60
|
+
console.log(`│ ${pad(label, 10)} ${pad(marker, 28)} ${pad(desc, W - 43)}│`);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
console.log(`┌${line}┐`);
|
|
64
|
+
console.log(`│${pad(' Plexor Settings', W - 2)}│`);
|
|
65
|
+
console.log(`├${line}┤`);
|
|
66
|
+
row('routing', routing.value, ROUTING_DESC[routing.value], routing.source);
|
|
67
|
+
row('agent', agent.value, AGENT_DESC[agent.value], agent.source);
|
|
68
|
+
row('provider', provider.value, PROVIDER_DESC[provider.value], provider.source);
|
|
69
|
+
console.log(`├${line}┤`);
|
|
70
|
+
console.log(`│${pad(' Set:', W - 2)}│`);
|
|
71
|
+
console.log(`│${pad(' /plexor-settings routing eco', W - 2)}│`);
|
|
72
|
+
console.log(`│${pad(' /plexor-settings agent danger-full-auto', W - 2)}│`);
|
|
73
|
+
console.log(`│${pad(' /plexor-settings provider anthropic', W - 2)}│`);
|
|
74
|
+
console.log(`├${line}┤`);
|
|
75
|
+
console.log(`│${pad(' Shortcuts:', W - 2)}│`);
|
|
76
|
+
console.log(`│${pad(' /plexor-routing /plexor-agent /plexor-provider', W - 2)}│`);
|
|
77
|
+
console.log(`└${line}┘`);
|
|
30
78
|
}
|
|
31
79
|
|
|
32
|
-
function
|
|
33
|
-
|
|
34
|
-
|
|
80
|
+
function setDimension(dimension, value, config) {
|
|
81
|
+
let validValues, aliases, configKey, configKeyAlt, envVar, defaultVal, descMap, label;
|
|
82
|
+
|
|
83
|
+
switch (dimension) {
|
|
84
|
+
case 'routing':
|
|
85
|
+
case 'mode':
|
|
86
|
+
validValues = ROUTING_MODES; aliases = ROUTING_ALIASES;
|
|
87
|
+
configKey = 'mode'; configKeyAlt = null; envVar = 'PLEXOR_MODE';
|
|
88
|
+
defaultVal = 'balanced'; descMap = ROUTING_DESC; label = 'Routing Mode';
|
|
89
|
+
break;
|
|
90
|
+
case 'agent':
|
|
91
|
+
case 'orchestration':
|
|
92
|
+
validValues = AGENT_MODES; aliases = AGENT_ALIASES;
|
|
93
|
+
configKey = 'orchestrationMode'; configKeyAlt = 'orchestration_mode'; envVar = 'PLEXOR_ORCHESTRATION_MODE';
|
|
94
|
+
defaultVal = 'autonomous'; descMap = AGENT_DESC; label = 'Agent Mode';
|
|
95
|
+
break;
|
|
96
|
+
case 'provider':
|
|
97
|
+
validValues = PROVIDERS; aliases = PROVIDER_ALIASES;
|
|
98
|
+
configKey = 'preferred_provider'; configKeyAlt = null; envVar = 'PLEXOR_PROVIDER';
|
|
99
|
+
defaultVal = 'auto'; descMap = PROVIDER_DESC; label = 'Provider';
|
|
100
|
+
break;
|
|
101
|
+
default:
|
|
102
|
+
console.error(`Unknown setting: "${dimension}"`);
|
|
103
|
+
console.error('Valid settings: routing, agent, provider');
|
|
104
|
+
process.exit(1);
|
|
35
105
|
}
|
|
36
|
-
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
37
|
-
}
|
|
38
106
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
107
|
+
let resolved = (value || '').toLowerCase().trim();
|
|
108
|
+
if (aliases[resolved]) resolved = aliases[resolved];
|
|
109
|
+
|
|
110
|
+
if (!validValues.includes(resolved)) {
|
|
111
|
+
console.error(`Invalid ${dimension} value: "${value}"`);
|
|
112
|
+
console.error(`Valid values: ${validValues.join(', ')}`);
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const current = readSetting(config, configKey, configKeyAlt, envVar, validValues, defaultVal);
|
|
117
|
+
|
|
118
|
+
if (current.source === 'environment' && resolved !== current.value) {
|
|
119
|
+
console.log(`Warning: ${envVar} environment variable is set to "${current.value}".`);
|
|
120
|
+
console.log(`Config will be updated, but env var takes priority.`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (resolved === current.value && current.source === 'config') {
|
|
124
|
+
console.log(`${label} is already set to "${resolved}".`);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
config.settings = config.settings || {};
|
|
129
|
+
config.settings[configKey] = resolved;
|
|
130
|
+
if (configKey === 'preferred_provider' && resolved !== 'auto') {
|
|
131
|
+
delete config.settings.preferred_model;
|
|
132
|
+
delete config.settings.preferredModel;
|
|
133
|
+
}
|
|
134
|
+
if (configKeyAlt && config.settings[configKeyAlt]) {
|
|
135
|
+
delete config.settings[configKeyAlt];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (!saveConfig(config)) { process.exit(1); }
|
|
139
|
+
|
|
140
|
+
console.log(`${label} updated: ${current.value} → ${resolved}`);
|
|
141
|
+
if (configKey === 'preferred_provider' && resolved !== 'auto') {
|
|
142
|
+
console.log(' Cleared preferred_model to keep provider/model force hints mutually exclusive.');
|
|
58
143
|
}
|
|
144
|
+
console.log(` ${descMap[resolved]}`);
|
|
145
|
+
console.log(` Takes effect on next request.`);
|
|
59
146
|
}
|
|
60
147
|
|
|
148
|
+
// ── Main ─────────────────────────────────────────────────────────────────────
|
|
149
|
+
|
|
61
150
|
function main() {
|
|
62
151
|
const args = process.argv.slice(2);
|
|
63
152
|
const config = loadConfig();
|
|
64
|
-
const settings = config.settings || {};
|
|
65
153
|
|
|
66
|
-
// No args - show current settings
|
|
67
154
|
if (args.length === 0) {
|
|
68
|
-
|
|
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(`└─────────────────────────────────────────────┘`);
|
|
155
|
+
showDashboard(config);
|
|
105
156
|
return;
|
|
106
157
|
}
|
|
107
158
|
|
|
108
|
-
// Get setting
|
|
109
159
|
if (args.length === 1) {
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
160
|
+
// Show one dimension's current value + options
|
|
161
|
+
const dim = args[0].toLowerCase();
|
|
162
|
+
let validValues, descMap, configKey, configKeyAlt, envVar, defaultVal, label;
|
|
163
|
+
switch (dim) {
|
|
164
|
+
case 'routing': case 'mode':
|
|
165
|
+
validValues = ROUTING_MODES; descMap = ROUTING_DESC;
|
|
166
|
+
configKey = 'mode'; configKeyAlt = null; envVar = 'PLEXOR_MODE';
|
|
167
|
+
defaultVal = 'balanced'; label = 'Routing Mode'; break;
|
|
168
|
+
case 'agent': case 'orchestration':
|
|
169
|
+
validValues = AGENT_MODES; descMap = AGENT_DESC;
|
|
170
|
+
configKey = 'orchestrationMode'; configKeyAlt = 'orchestration_mode'; envVar = 'PLEXOR_ORCHESTRATION_MODE';
|
|
171
|
+
defaultVal = 'autonomous'; label = 'Agent Mode'; break;
|
|
172
|
+
case 'provider':
|
|
173
|
+
validValues = PROVIDERS; descMap = PROVIDER_DESC;
|
|
174
|
+
configKey = 'preferred_provider'; configKeyAlt = null; envVar = 'PLEXOR_PROVIDER';
|
|
175
|
+
defaultVal = 'auto'; label = 'Provider'; break;
|
|
176
|
+
default:
|
|
177
|
+
console.error(`Unknown setting: "${dim}". Valid: routing, agent, provider`);
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
const current = readSetting(config, configKey, configKeyAlt, envVar, validValues, defaultVal);
|
|
181
|
+
console.log(`${label}: ${current.value} (${current.source})`);
|
|
182
|
+
console.log('Options:');
|
|
183
|
+
for (const v of validValues) {
|
|
184
|
+
const marker = v === current.value ? '>>' : ' ';
|
|
185
|
+
console.log(` ${marker} ${v.padEnd(18)} ${descMap[v]}`);
|
|
118
186
|
}
|
|
119
|
-
|
|
120
|
-
console.log(`${normalizedKey}: ${value}`);
|
|
121
187
|
return;
|
|
122
188
|
}
|
|
123
189
|
|
|
124
|
-
|
|
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
|
-
}
|
|
190
|
+
setDimension(args[0], args[1], config);
|
|
153
191
|
}
|
|
154
192
|
|
|
155
193
|
main();
|