@plexor-dev/claude-code-plugin-staging 0.1.0-beta.14 → 0.1.0-beta.16
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-agent.js +84 -0
- package/commands/plexor-agent.md +36 -0
- package/commands/plexor-provider.js +84 -0
- package/commands/plexor-provider.md +37 -0
- package/commands/plexor-routing.js +77 -0
- package/commands/plexor-routing.md +37 -0
- package/commands/plexor-settings.js +186 -0
- package/commands/plexor-settings.md +52 -0
- package/hooks/intercept.js +139 -10
- package/hooks/track-response.js +300 -0
- package/lib/config-utils.js +74 -0
- package/lib/config.js +9 -2
- package/lib/logger.js +64 -5
- package/lib/settings-manager.js +20 -6
- package/package.json +6 -2
- package/scripts/postinstall.js +161 -35
- package/scripts/uninstall.js +26 -3
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Plexor Agent — set agent autonomy level.
|
|
5
|
+
*
|
|
6
|
+
* Agent modes control how the AI agent behaves:
|
|
7
|
+
* supervised: Agent describes actions, waits for your confirmation
|
|
8
|
+
* autonomous: Agent acts independently within safe bounds (default)
|
|
9
|
+
* danger-full-auto: Full autonomy, no guardrails — forces tool execution
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* /plexor-agent Show current agent mode
|
|
13
|
+
* /plexor-agent supervised Confirm before every action
|
|
14
|
+
* /plexor-agent autonomous Smart autonomy (default)
|
|
15
|
+
* /plexor-agent danger-full-auto No guardrails
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const { loadConfig, saveConfig, readSetting } = require('../lib/config-utils');
|
|
19
|
+
|
|
20
|
+
const VALID = ['supervised', 'autonomous', 'danger-full-auto'];
|
|
21
|
+
const DESC = {
|
|
22
|
+
supervised: 'Confirm before acting',
|
|
23
|
+
autonomous: 'Acts within safe bounds (default)',
|
|
24
|
+
'danger-full-auto': 'Full autonomy, no guardrails'
|
|
25
|
+
};
|
|
26
|
+
const ALIASES = {
|
|
27
|
+
auto: 'autonomous',
|
|
28
|
+
fullauto: 'danger-full-auto',
|
|
29
|
+
'full-auto': 'danger-full-auto',
|
|
30
|
+
full_auto: 'danger-full-auto',
|
|
31
|
+
danger: 'danger-full-auto'
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
function main() {
|
|
35
|
+
const args = process.argv.slice(2);
|
|
36
|
+
const config = loadConfig();
|
|
37
|
+
const current = readSetting(config, 'orchestrationMode', 'orchestration_mode', 'PLEXOR_ORCHESTRATION_MODE', VALID, 'autonomous');
|
|
38
|
+
|
|
39
|
+
if (args.length === 0) {
|
|
40
|
+
console.log(`Agent Mode: ${current.value} (${current.source})`);
|
|
41
|
+
console.log(` ${DESC[current.value]}`);
|
|
42
|
+
console.log('');
|
|
43
|
+
console.log('Options:');
|
|
44
|
+
for (const v of VALID) {
|
|
45
|
+
const marker = v === current.value ? '>>' : ' ';
|
|
46
|
+
console.log(` ${marker} ${v.padEnd(20)} ${DESC[v]}`);
|
|
47
|
+
}
|
|
48
|
+
console.log('');
|
|
49
|
+
console.log('Set: /plexor-agent <mode>');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let requested = args[0].toLowerCase().trim();
|
|
54
|
+
if (ALIASES[requested]) requested = ALIASES[requested];
|
|
55
|
+
|
|
56
|
+
if (!VALID.includes(requested)) {
|
|
57
|
+
console.error(`Invalid agent mode: "${args[0]}"`);
|
|
58
|
+
console.error(`Valid: ${VALID.join(', ')}`);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (current.source === 'environment' && requested !== current.value) {
|
|
63
|
+
console.log(`Warning: PLEXOR_ORCHESTRATION_MODE env var is set to "${current.value}". Config updated but env var takes priority.`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (requested === current.value && current.source === 'config') {
|
|
67
|
+
console.log(`Already set to "${requested}".`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
config.settings = config.settings || {};
|
|
72
|
+
config.settings.orchestrationMode = requested;
|
|
73
|
+
if (config.settings.orchestration_mode) delete config.settings.orchestration_mode;
|
|
74
|
+
if (!saveConfig(config)) { process.exit(1); }
|
|
75
|
+
|
|
76
|
+
console.log(`Agent mode: ${current.value} → ${requested}`);
|
|
77
|
+
console.log(` ${DESC[requested]}`);
|
|
78
|
+
if (requested === 'danger-full-auto') {
|
|
79
|
+
console.log(' Warning: This forces tool execution on every turn with tools.');
|
|
80
|
+
}
|
|
81
|
+
console.log(' Takes effect on next request.');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
main();
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Set Plexor agent autonomy — supervised, autonomous, or danger-full-auto (user)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
**Step 1: Check if arguments were provided.**
|
|
6
|
+
|
|
7
|
+
If `$ARGUMENTS` contains a value (e.g., `/plexor-agent autonomous`), apply it directly:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
node ~/.claude/plugins/plexor/commands/plexor-agent.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-agent`), first show the current state:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
node ~/.claude/plugins/plexor/commands/plexor-agent.js
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Then immediately use **AskUserQuestion** to let the user pick a mode:
|
|
22
|
+
|
|
23
|
+
- **Question**: "Which agent autonomy mode?"
|
|
24
|
+
- **Header**: "Agent mode"
|
|
25
|
+
- **Options** (exactly 3):
|
|
26
|
+
1. **supervised** — "Confirm before every action"
|
|
27
|
+
2. **autonomous (Recommended)** — "Acts within safe bounds, default mode"
|
|
28
|
+
3. **danger-full-auto** — "Full autonomy, no guardrails"
|
|
29
|
+
|
|
30
|
+
**Step 3: After the user selects**, apply their choice:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
node ~/.claude/plugins/plexor/commands/plexor-agent.js <selected_value>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Present the output and STOP. Do NOT re-execute commands or call other tools.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
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
|
|
21
|
+
*/
|
|
22
|
+
|
|
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)'
|
|
35
|
+
};
|
|
36
|
+
const ALIASES = { claude: 'anthropic' };
|
|
37
|
+
|
|
38
|
+
function main() {
|
|
39
|
+
const args = process.argv.slice(2);
|
|
40
|
+
const config = loadConfig();
|
|
41
|
+
const current = readSetting(config, 'preferred_provider', null, 'PLEXOR_PROVIDER', VALID, 'auto');
|
|
42
|
+
|
|
43
|
+
if (args.length === 0) {
|
|
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]}`);
|
|
51
|
+
}
|
|
52
|
+
console.log('');
|
|
53
|
+
console.log('Set: /plexor-provider <name>');
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let requested = args[0].toLowerCase().trim();
|
|
58
|
+
if (ALIASES[requested]) requested = ALIASES[requested];
|
|
59
|
+
|
|
60
|
+
if (!VALID.includes(requested)) {
|
|
61
|
+
console.error(`Invalid provider: "${args[0]}"`);
|
|
62
|
+
console.error(`Valid: ${VALID.join(', ')}`);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
|
|
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
|
+
}
|
|
69
|
+
|
|
70
|
+
if (requested === current.value && current.source === 'config') {
|
|
71
|
+
console.log(`Already set to "${requested}".`);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
config.settings = config.settings || {};
|
|
76
|
+
config.settings.preferred_provider = requested;
|
|
77
|
+
if (!saveConfig(config)) { process.exit(1); }
|
|
78
|
+
|
|
79
|
+
console.log(`Provider: ${current.value} → ${requested}`);
|
|
80
|
+
console.log(` ${DESC[requested]}`);
|
|
81
|
+
console.log(' Takes effect on next request.');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
main();
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Set Plexor LLM provider — auto, anthropic, openai, deepseek, gemini, etc. (user)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
**Step 1: Check if arguments were provided.**
|
|
6
|
+
|
|
7
|
+
If `$ARGUMENTS` contains a value (e.g., `/plexor-provider anthropic`), apply it directly:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
node ~/.claude/plugins/plexor/commands/plexor-provider.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-provider`), first show the current state:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
node ~/.claude/plugins/plexor/commands/plexor-provider.js
|
|
19
|
+
```
|
|
20
|
+
|
|
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)"
|
|
30
|
+
|
|
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
|
+
```
|
|
36
|
+
|
|
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.
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
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
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const { loadConfig, saveConfig, readSetting } = require('../lib/config-utils');
|
|
14
|
+
|
|
15
|
+
// ── Definitions ──────────────────────────────────────────────────────────────
|
|
16
|
+
|
|
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'
|
|
23
|
+
};
|
|
24
|
+
const ROUTING_ALIASES = { cost: 'eco' };
|
|
25
|
+
|
|
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}┘`);
|
|
78
|
+
}
|
|
79
|
+
|
|
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);
|
|
105
|
+
}
|
|
106
|
+
|
|
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 (configKeyAlt && config.settings[configKeyAlt]) {
|
|
131
|
+
delete config.settings[configKeyAlt];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (!saveConfig(config)) { process.exit(1); }
|
|
135
|
+
|
|
136
|
+
console.log(`${label} updated: ${current.value} → ${resolved}`);
|
|
137
|
+
console.log(` ${descMap[resolved]}`);
|
|
138
|
+
console.log(` Takes effect on next request.`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ── Main ─────────────────────────────────────────────────────────────────────
|
|
142
|
+
|
|
143
|
+
function main() {
|
|
144
|
+
const args = process.argv.slice(2);
|
|
145
|
+
const config = loadConfig();
|
|
146
|
+
|
|
147
|
+
if (args.length === 0) {
|
|
148
|
+
showDashboard(config);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (args.length === 1) {
|
|
153
|
+
// Show one dimension's current value + options
|
|
154
|
+
const dim = args[0].toLowerCase();
|
|
155
|
+
let validValues, descMap, configKey, configKeyAlt, envVar, defaultVal, label;
|
|
156
|
+
switch (dim) {
|
|
157
|
+
case 'routing': case 'mode':
|
|
158
|
+
validValues = ROUTING_MODES; descMap = ROUTING_DESC;
|
|
159
|
+
configKey = 'mode'; configKeyAlt = null; envVar = 'PLEXOR_MODE';
|
|
160
|
+
defaultVal = 'balanced'; label = 'Routing Mode'; break;
|
|
161
|
+
case 'agent': case 'orchestration':
|
|
162
|
+
validValues = AGENT_MODES; descMap = AGENT_DESC;
|
|
163
|
+
configKey = 'orchestrationMode'; configKeyAlt = 'orchestration_mode'; envVar = 'PLEXOR_ORCHESTRATION_MODE';
|
|
164
|
+
defaultVal = 'autonomous'; label = 'Agent Mode'; break;
|
|
165
|
+
case 'provider':
|
|
166
|
+
validValues = PROVIDERS; descMap = PROVIDER_DESC;
|
|
167
|
+
configKey = 'preferred_provider'; configKeyAlt = null; envVar = 'PLEXOR_PROVIDER';
|
|
168
|
+
defaultVal = 'auto'; label = 'Provider'; break;
|
|
169
|
+
default:
|
|
170
|
+
console.error(`Unknown setting: "${dim}". Valid: routing, agent, provider`);
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
const current = readSetting(config, configKey, configKeyAlt, envVar, validValues, defaultVal);
|
|
174
|
+
console.log(`${label}: ${current.value} (${current.source})`);
|
|
175
|
+
console.log('Options:');
|
|
176
|
+
for (const v of validValues) {
|
|
177
|
+
const marker = v === current.value ? '>>' : ' ';
|
|
178
|
+
console.log(` ${marker} ${v.padEnd(18)} ${descMap[v]}`);
|
|
179
|
+
}
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
setDimension(args[0], args[1], config);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
main();
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: View and change Plexor settings — routing mode, agent autonomy, LLM provider (user)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
**Step 1: Check if arguments were provided.**
|
|
6
|
+
|
|
7
|
+
If `$ARGUMENTS` contains both a dimension AND a value (e.g., `/plexor-settings routing eco`), apply it directly:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
node ~/.claude/plugins/plexor/commands/plexor-settings.js $ARGUMENTS
|
|
11
|
+
```
|
|
12
|
+
|
|
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:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
node ~/.claude/plugins/plexor/commands/plexor-settings.js <dimension> <selected_value>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Present the output and STOP.
|
|
45
|
+
|
|
46
|
+
**Step 3: If NO arguments were provided** (just `/plexor-settings`), show the dashboard:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
node ~/.claude/plugins/plexor/commands/plexor-settings.js
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Present the output to the user and STOP. Do NOT call any other tools.
|