@plexor-dev/claude-code-plugin-staging 0.1.0-beta.13 → 0.1.0-beta.15
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 +11 -0
- package/commands/plexor-provider.js +84 -0
- package/commands/plexor-provider.md +11 -0
- package/commands/plexor-routing.js +77 -0
- package/commands/plexor-routing.md +11 -0
- package/commands/plexor-settings.js +186 -0
- package/commands/plexor-settings.md +15 -0
- package/hooks/intercept.js +109 -9
- package/lib/config-utils.js +74 -0
- package/lib/config.js +9 -2
- package/lib/logger.js +21 -4
- package/package.json +6 -2
|
@@ -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,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Set Plexor agent autonomy — supervised, autonomous, or danger-full-auto (user)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
**RULE: Execute the bash command below EXACTLY ONCE. After the Bash tool returns output, your ONLY action is to present that output to the user. DO NOT re-execute the command. DO NOT call any other tools.**
|
|
6
|
+
|
|
7
|
+
Show current agent mode (no args) or set it (supervised, autonomous, danger-full-auto).
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
node ~/.claude/plugins/plexor/commands/plexor-agent.js $ARGUMENTS
|
|
11
|
+
```
|
|
@@ -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,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Set Plexor LLM provider — auto, anthropic, openai, deepseek, gemini, etc. (user)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
**RULE: Execute the bash command below EXACTLY ONCE. After the Bash tool returns output, your ONLY action is to present that output to the user. DO NOT re-execute the command. DO NOT call any other tools.**
|
|
6
|
+
|
|
7
|
+
Show current provider (no args) or set it (auto, anthropic, openai, deepseek, mistral, gemini, grok, cohere).
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
node ~/.claude/plugins/plexor/commands/plexor-provider.js $ARGUMENTS
|
|
11
|
+
```
|
|
@@ -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,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Set Plexor routing mode — eco, balanced, quality, or passthrough (user)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
**RULE: Execute the bash command below EXACTLY ONCE. After the Bash tool returns output, your ONLY action is to present that output to the user. DO NOT re-execute the command. DO NOT call any other tools.**
|
|
6
|
+
|
|
7
|
+
Show current routing mode (no args) or set it (eco, balanced, quality, passthrough).
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
node ~/.claude/plugins/plexor/commands/plexor-routing.js $ARGUMENTS
|
|
11
|
+
```
|
|
@@ -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,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: View and change Plexor settings — routing mode, agent autonomy, LLM provider (user)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
**RULE: Execute the bash command below EXACTLY ONCE. After the Bash tool returns output, your ONLY action is to present that output to the user. DO NOT re-execute the command. DO NOT call any other tools.**
|
|
6
|
+
|
|
7
|
+
Show all settings (no args), or set a specific dimension:
|
|
8
|
+
- `/plexor-settings` — dashboard
|
|
9
|
+
- `/plexor-settings routing eco` — set routing mode
|
|
10
|
+
- `/plexor-settings agent danger-full-auto` — set agent autonomy
|
|
11
|
+
- `/plexor-settings provider anthropic` — set LLM provider
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
node ~/.claude/plugins/plexor/commands/plexor-settings.js $ARGUMENTS
|
|
15
|
+
```
|
package/hooks/intercept.js
CHANGED
|
@@ -35,6 +35,93 @@ function generateRequestId(prefix = 'pass') {
|
|
|
35
35
|
return `${prefix}_${timestamp}_${random}`;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
const VALID_ORCHESTRATION_MODES = new Set([
|
|
39
|
+
'supervised',
|
|
40
|
+
'autonomous',
|
|
41
|
+
'danger-full-auto'
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
const VALID_GATEWAY_MODES = new Set(['eco', 'balanced', 'quality', 'passthrough', 'cost']);
|
|
45
|
+
const VALID_PROVIDER_HINTS = new Set([
|
|
46
|
+
'auto',
|
|
47
|
+
'anthropic',
|
|
48
|
+
'claude',
|
|
49
|
+
'openai',
|
|
50
|
+
'deepseek',
|
|
51
|
+
'mistral',
|
|
52
|
+
'gemini',
|
|
53
|
+
'grok',
|
|
54
|
+
'cohere'
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
function normalizeOrchestrationMode(mode) {
|
|
58
|
+
if (typeof mode !== 'string') {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const normalized = mode.trim().toLowerCase();
|
|
62
|
+
if (!VALID_ORCHESTRATION_MODES.has(normalized)) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
// Accept legacy 'full-auto' as alias for 'danger-full-auto'
|
|
66
|
+
if (normalized === 'full-auto') return 'danger-full-auto';
|
|
67
|
+
return normalized;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function normalizeGatewayMode(mode) {
|
|
71
|
+
if (typeof mode !== 'string') {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
const normalized = mode.trim().toLowerCase();
|
|
75
|
+
if (!VALID_GATEWAY_MODES.has(normalized)) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
return normalized === 'cost' ? 'eco' : normalized;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function normalizePreferredProvider(provider) {
|
|
82
|
+
if (typeof provider !== 'string') {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
const normalized = provider.trim().toLowerCase();
|
|
86
|
+
if (!VALID_PROVIDER_HINTS.has(normalized)) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
return normalized;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function resolveOrchestrationMode(settings) {
|
|
93
|
+
const envMode = normalizeOrchestrationMode(process.env.PLEXOR_ORCHESTRATION_MODE);
|
|
94
|
+
if (envMode) {
|
|
95
|
+
return envMode;
|
|
96
|
+
}
|
|
97
|
+
const cfgMode = normalizeOrchestrationMode(
|
|
98
|
+
settings?.orchestrationMode || settings?.orchestration_mode
|
|
99
|
+
);
|
|
100
|
+
return cfgMode || 'autonomous';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function resolveGatewayMode(settings) {
|
|
104
|
+
const envMode = normalizeGatewayMode(process.env.PLEXOR_MODE);
|
|
105
|
+
if (envMode) {
|
|
106
|
+
return envMode;
|
|
107
|
+
}
|
|
108
|
+
const cfgMode = normalizeGatewayMode(settings?.mode);
|
|
109
|
+
return cfgMode || 'balanced';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function resolvePreferredProvider(settings) {
|
|
113
|
+
const envProvider = normalizePreferredProvider(
|
|
114
|
+
process.env.PLEXOR_PROVIDER || process.env.PLEXOR_PREFERRED_PROVIDER
|
|
115
|
+
);
|
|
116
|
+
if (envProvider) {
|
|
117
|
+
return envProvider;
|
|
118
|
+
}
|
|
119
|
+
const cfgProvider = normalizePreferredProvider(
|
|
120
|
+
settings?.preferredProvider || settings?.preferred_provider
|
|
121
|
+
);
|
|
122
|
+
return cfgProvider || 'auto';
|
|
123
|
+
}
|
|
124
|
+
|
|
38
125
|
// Try to load lib modules, fall back to inline implementations
|
|
39
126
|
let ConfigManager, SessionManager, LocalCache, Logger, PlexorClient;
|
|
40
127
|
let config, session, cache, logger;
|
|
@@ -73,7 +160,10 @@ try {
|
|
|
73
160
|
apiUrl: cfg.settings?.apiUrl || 'https://api.plexor.dev',
|
|
74
161
|
timeout: cfg.settings?.timeout || 5000,
|
|
75
162
|
localCacheEnabled: cfg.settings?.localCacheEnabled ?? false,
|
|
76
|
-
mode: cfg.settings?.mode || 'balanced'
|
|
163
|
+
mode: cfg.settings?.mode || 'balanced',
|
|
164
|
+
preferredProvider: cfg.settings?.preferred_provider || 'auto',
|
|
165
|
+
orchestrationMode:
|
|
166
|
+
cfg.settings?.orchestrationMode || cfg.settings?.orchestration_mode || 'autonomous'
|
|
77
167
|
};
|
|
78
168
|
} catch {
|
|
79
169
|
return { enabled: false };
|
|
@@ -190,6 +280,11 @@ async function main() {
|
|
|
190
280
|
return output(request); // Completely clean — no metadata added
|
|
191
281
|
}
|
|
192
282
|
|
|
283
|
+
const settings = await config.load();
|
|
284
|
+
const orchestrationMode = resolveOrchestrationMode(settings);
|
|
285
|
+
const gatewayMode = resolveGatewayMode(settings);
|
|
286
|
+
const preferredProvider = resolvePreferredProvider(settings);
|
|
287
|
+
|
|
193
288
|
// Phase 3 Hypervisor Mode Detection
|
|
194
289
|
// When ANTHROPIC_BASE_URL points to Plexor, all intelligence is server-side
|
|
195
290
|
// The plugin just passes through - server handles optimization, routing, quality
|
|
@@ -199,14 +294,21 @@ async function main() {
|
|
|
199
294
|
if (isHypervisorMode) {
|
|
200
295
|
// HYPERVISOR MODE: Server handles everything
|
|
201
296
|
// Just pass through with minimal metadata for session tracking
|
|
202
|
-
logger.debug('
|
|
297
|
+
logger.debug('Hypervisor mode active - server handles all optimization');
|
|
203
298
|
|
|
204
299
|
// Add session tracking metadata (server will use this for analytics)
|
|
205
300
|
return output({
|
|
206
301
|
...request,
|
|
302
|
+
plexor_mode: gatewayMode,
|
|
303
|
+
...(preferredProvider !== 'auto' ? { plexor_provider: preferredProvider } : {}),
|
|
304
|
+
plexor_orchestration_mode: orchestrationMode,
|
|
207
305
|
_plexor_client: {
|
|
306
|
+
...(request._plexor_client || {}),
|
|
208
307
|
mode: 'hypervisor',
|
|
209
308
|
plugin_version: '0.1.0-beta.18',
|
|
309
|
+
orchestration_mode: orchestrationMode,
|
|
310
|
+
plexor_mode: gatewayMode,
|
|
311
|
+
preferred_provider: preferredProvider,
|
|
210
312
|
cwd: process.cwd(),
|
|
211
313
|
timestamp: Date.now(),
|
|
212
314
|
}
|
|
@@ -249,8 +351,6 @@ async function main() {
|
|
|
249
351
|
});
|
|
250
352
|
}
|
|
251
353
|
|
|
252
|
-
const settings = await config.load();
|
|
253
|
-
|
|
254
354
|
if (!settings.enabled) {
|
|
255
355
|
logger.debug('Plexor disabled, passing through');
|
|
256
356
|
session.recordPassthrough();
|
|
@@ -293,7 +393,7 @@ async function main() {
|
|
|
293
393
|
const cachedResponse = await cache.get(cacheKey);
|
|
294
394
|
|
|
295
395
|
if (cachedResponse && settings.localCacheEnabled) {
|
|
296
|
-
logger.info('
|
|
396
|
+
logger.info('Local cache hit');
|
|
297
397
|
session.recordCacheHit();
|
|
298
398
|
return output({
|
|
299
399
|
...request,
|
|
@@ -321,10 +421,10 @@ async function main() {
|
|
|
321
421
|
|
|
322
422
|
const savingsPercent = ((result.original_tokens - result.optimized_tokens) / result.original_tokens * 100).toFixed(1);
|
|
323
423
|
|
|
324
|
-
logger.info(`
|
|
424
|
+
logger.info(`Optimized: ${result.original_tokens} → ${result.optimized_tokens} tokens (${savingsPercent}% saved)`);
|
|
325
425
|
|
|
326
426
|
if (result.recommended_provider !== 'anthropic') {
|
|
327
|
-
logger.info(`
|
|
427
|
+
logger.info(`Recommended: ${result.recommended_provider} (~$${result.estimated_cost.toFixed(4)})`);
|
|
328
428
|
}
|
|
329
429
|
|
|
330
430
|
const optimizedRequest = {
|
|
@@ -360,7 +460,7 @@ async function main() {
|
|
|
360
460
|
return output(optimizedRequest);
|
|
361
461
|
|
|
362
462
|
} catch (error) {
|
|
363
|
-
logger.error(`
|
|
463
|
+
logger.error(`Error: ${error.message}`);
|
|
364
464
|
logger.debug(error.stack);
|
|
365
465
|
|
|
366
466
|
const errorRequestId = generateRequestId('error'); // Issue #701: Add request_id for tracking
|
|
@@ -625,6 +725,6 @@ function requiresToolExecution(request) {
|
|
|
625
725
|
}
|
|
626
726
|
|
|
627
727
|
main().catch((error) => {
|
|
628
|
-
console.error(
|
|
728
|
+
console.error(`\x1b[1m\x1b[37m\x1b[41m PLEXOR \x1b[0m \x1b[31mFatal: ${error.message}\x1b[0m`);
|
|
629
729
|
process.exit(1);
|
|
630
730
|
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared config utilities for Plexor slash commands.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const crypto = require('crypto');
|
|
8
|
+
const { PLEXOR_DIR, CONFIG_PATH } = require('./constants');
|
|
9
|
+
|
|
10
|
+
function loadConfig() {
|
|
11
|
+
try {
|
|
12
|
+
if (!fs.existsSync(CONFIG_PATH)) {
|
|
13
|
+
return { version: 1, auth: {}, settings: {} };
|
|
14
|
+
}
|
|
15
|
+
const data = fs.readFileSync(CONFIG_PATH, 'utf8');
|
|
16
|
+
if (!data || data.trim() === '') {
|
|
17
|
+
return { version: 1, auth: {}, settings: {} };
|
|
18
|
+
}
|
|
19
|
+
const config = JSON.parse(data);
|
|
20
|
+
if (typeof config !== 'object' || config === null) {
|
|
21
|
+
return { version: 1, auth: {}, settings: {} };
|
|
22
|
+
}
|
|
23
|
+
return config;
|
|
24
|
+
} catch (err) {
|
|
25
|
+
if (err instanceof SyntaxError) {
|
|
26
|
+
try { fs.copyFileSync(CONFIG_PATH, CONFIG_PATH + '.corrupted'); } catch { /* ignore */ }
|
|
27
|
+
}
|
|
28
|
+
return { version: 1, auth: {}, settings: {} };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function saveConfig(config) {
|
|
33
|
+
try {
|
|
34
|
+
if (!fs.existsSync(PLEXOR_DIR)) {
|
|
35
|
+
fs.mkdirSync(PLEXOR_DIR, { recursive: true, mode: 0o700 });
|
|
36
|
+
}
|
|
37
|
+
const tempId = crypto.randomBytes(8).toString('hex');
|
|
38
|
+
const tempPath = path.join(PLEXOR_DIR, `.config.${tempId}.tmp`);
|
|
39
|
+
fs.writeFileSync(tempPath, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
40
|
+
fs.renameSync(tempPath, CONFIG_PATH);
|
|
41
|
+
return true;
|
|
42
|
+
} catch (err) {
|
|
43
|
+
if (err.code === 'EACCES' || err.code === 'EPERM') {
|
|
44
|
+
console.error('Error: Cannot write to ~/.plexor/config.json');
|
|
45
|
+
} else {
|
|
46
|
+
console.error('Failed to save config:', err.message);
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Read a setting with env-var → config → default precedence.
|
|
54
|
+
* @param {object} config - Loaded config object
|
|
55
|
+
* @param {string} configKey - Primary key in config.settings (camelCase)
|
|
56
|
+
* @param {string|null} configKeyAlt - Alternative key (snake_case legacy)
|
|
57
|
+
* @param {string} envVar - Environment variable name
|
|
58
|
+
* @param {string[]} validValues - Accepted values
|
|
59
|
+
* @param {string} defaultValue - Fallback
|
|
60
|
+
* @returns {{ value: string, source: string }}
|
|
61
|
+
*/
|
|
62
|
+
function readSetting(config, configKey, configKeyAlt, envVar, validValues, defaultValue) {
|
|
63
|
+
const env = process.env[envVar];
|
|
64
|
+
if (env && validValues.includes(env.toLowerCase())) {
|
|
65
|
+
return { value: env.toLowerCase(), source: 'environment' };
|
|
66
|
+
}
|
|
67
|
+
const cfg = config.settings?.[configKey] || (configKeyAlt && config.settings?.[configKeyAlt]);
|
|
68
|
+
if (cfg && validValues.includes(cfg.toLowerCase())) {
|
|
69
|
+
return { value: cfg.toLowerCase(), source: 'config' };
|
|
70
|
+
}
|
|
71
|
+
return { value: defaultValue, source: 'default' };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
module.exports = { loadConfig, saveConfig, readSetting };
|
package/lib/config.js
CHANGED
|
@@ -22,7 +22,9 @@ class ConfigManager {
|
|
|
22
22
|
timeout: cfg.settings?.timeout || DEFAULT_TIMEOUT,
|
|
23
23
|
localCacheEnabled: cfg.settings?.localCacheEnabled ?? false,
|
|
24
24
|
mode: cfg.settings?.mode || 'balanced',
|
|
25
|
-
preferredProvider: cfg.settings?.preferred_provider || 'auto'
|
|
25
|
+
preferredProvider: cfg.settings?.preferred_provider || 'auto',
|
|
26
|
+
orchestrationMode:
|
|
27
|
+
cfg.settings?.orchestrationMode || cfg.settings?.orchestration_mode || 'autonomous'
|
|
26
28
|
};
|
|
27
29
|
} catch {
|
|
28
30
|
return { enabled: false, apiKey: '', apiUrl: DEFAULT_API_URL };
|
|
@@ -52,7 +54,12 @@ class ConfigManager {
|
|
|
52
54
|
timeout: config.timeout ?? existing.settings?.timeout,
|
|
53
55
|
localCacheEnabled: config.localCacheEnabled ?? existing.settings?.localCacheEnabled,
|
|
54
56
|
mode: config.mode ?? existing.settings?.mode,
|
|
55
|
-
preferred_provider: config.preferredProvider ?? existing.settings?.preferred_provider
|
|
57
|
+
preferred_provider: config.preferredProvider ?? existing.settings?.preferred_provider,
|
|
58
|
+
orchestrationMode:
|
|
59
|
+
config.orchestrationMode ??
|
|
60
|
+
config.orchestration_mode ??
|
|
61
|
+
existing.settings?.orchestrationMode ??
|
|
62
|
+
existing.settings?.orchestration_mode
|
|
56
63
|
}
|
|
57
64
|
};
|
|
58
65
|
|
package/lib/logger.js
CHANGED
|
@@ -2,8 +2,25 @@
|
|
|
2
2
|
* Plexor Logger
|
|
3
3
|
*
|
|
4
4
|
* Simple logger that outputs to stderr to avoid interfering with stdout JSON.
|
|
5
|
+
* Uses ANSI-colored badges for branded Plexor messages.
|
|
5
6
|
*/
|
|
6
7
|
|
|
8
|
+
// ANSI color codes for branded badge output
|
|
9
|
+
const RESET = '\x1b[0m';
|
|
10
|
+
const BOLD = '\x1b[1m';
|
|
11
|
+
const DIM = '\x1b[2m';
|
|
12
|
+
const WHITE = '\x1b[37m';
|
|
13
|
+
const YELLOW_FG = '\x1b[33m';
|
|
14
|
+
const RED_FG = '\x1b[31m';
|
|
15
|
+
const BLUE_BG = '\x1b[44m';
|
|
16
|
+
const YELLOW_BG = '\x1b[43m';
|
|
17
|
+
const RED_BG = '\x1b[41m';
|
|
18
|
+
|
|
19
|
+
// Pre-built badge strings
|
|
20
|
+
const BADGE_INFO = `${BOLD}${WHITE}${BLUE_BG} PLEXOR ${RESET}`;
|
|
21
|
+
const BADGE_WARN = `${BOLD}${WHITE}${YELLOW_BG} PLEXOR ${RESET}`;
|
|
22
|
+
const BADGE_ERROR = `${BOLD}${WHITE}${RED_BG} PLEXOR ${RESET}`;
|
|
23
|
+
|
|
7
24
|
class Logger {
|
|
8
25
|
constructor(component = 'plexor') {
|
|
9
26
|
this.component = component;
|
|
@@ -12,23 +29,23 @@ class Logger {
|
|
|
12
29
|
|
|
13
30
|
debug(msg, data = null) {
|
|
14
31
|
if (this.debug_enabled) {
|
|
15
|
-
const output = data ?
|
|
32
|
+
const output = data ? `${DIM}[${this.component}]${RESET} ${msg} ${JSON.stringify(data)}` : `${DIM}[${this.component}]${RESET} ${msg}`;
|
|
16
33
|
console.error(output);
|
|
17
34
|
}
|
|
18
35
|
}
|
|
19
36
|
|
|
20
37
|
info(msg, data = null) {
|
|
21
|
-
const output = data ? `${msg} ${JSON.stringify(data)}` : msg
|
|
38
|
+
const output = data ? `${BADGE_INFO} ${msg} ${JSON.stringify(data)}` : `${BADGE_INFO} ${msg}`;
|
|
22
39
|
console.error(output);
|
|
23
40
|
}
|
|
24
41
|
|
|
25
42
|
warn(msg, data = null) {
|
|
26
|
-
const output = data ?
|
|
43
|
+
const output = data ? `${BADGE_WARN} ${YELLOW_FG}${msg} ${JSON.stringify(data)}${RESET}` : `${BADGE_WARN} ${YELLOW_FG}${msg}${RESET}`;
|
|
27
44
|
console.error(output);
|
|
28
45
|
}
|
|
29
46
|
|
|
30
47
|
error(msg, data = null) {
|
|
31
|
-
const output = data ?
|
|
48
|
+
const output = data ? `${BADGE_ERROR} ${RED_FG}${msg} ${JSON.stringify(data)}${RESET}` : `${BADGE_ERROR} ${RED_FG}${msg}${RESET}`;
|
|
32
49
|
console.error(output);
|
|
33
50
|
}
|
|
34
51
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plexor-dev/claude-code-plugin-staging",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.15",
|
|
4
4
|
"description": "STAGING - LLM cost optimization plugin for Claude Code (internal testing)",
|
|
5
5
|
"main": "lib/constants.js",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,11 @@
|
|
|
8
8
|
"plexor-enabled": "./commands/plexor-enabled.js",
|
|
9
9
|
"plexor-login": "./commands/plexor-login.js",
|
|
10
10
|
"plexor-logout": "./commands/plexor-logout.js",
|
|
11
|
-
"plexor-uninstall": "./commands/plexor-uninstall.js"
|
|
11
|
+
"plexor-uninstall": "./commands/plexor-uninstall.js",
|
|
12
|
+
"plexor-settings": "./commands/plexor-settings.js",
|
|
13
|
+
"plexor-routing": "./commands/plexor-routing.js",
|
|
14
|
+
"plexor-agent": "./commands/plexor-agent.js",
|
|
15
|
+
"plexor-provider": "./commands/plexor-provider.js"
|
|
12
16
|
},
|
|
13
17
|
"scripts": {
|
|
14
18
|
"postinstall": "node scripts/postinstall.js",
|