@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.
@@ -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
+ ```
@@ -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('[Plexor] Hypervisor mode active - server handles all optimization');
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('[Plexor] Local cache hit');
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(`[Plexor] Optimized: ${result.original_tokens} → ${result.optimized_tokens} tokens (${savingsPercent}% saved)`);
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(`[Plexor] Recommended: ${result.recommended_provider} (~$${result.estimated_cost.toFixed(4)})`);
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(`[Plexor] Error: ${error.message}`);
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(`[Plexor] Fatal error: ${error.message}`);
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 ? `[DEBUG][${this.component}] ${msg} ${JSON.stringify(data)}` : `[DEBUG][${this.component}] ${msg}`;
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 ? `[WARN][${this.component}] ${msg} ${JSON.stringify(data)}` : `[WARN][${this.component}] ${msg}`;
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 ? `[ERROR][${this.component}] ${msg} ${JSON.stringify(data)}` : `[ERROR][${this.component}] ${msg}`;
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.13",
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",