@plexor-dev/claude-code-plugin-staging 0.1.0-beta.16 → 0.1.0-beta.17
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-provider.js +7 -0
- package/commands/plexor-settings.js +7 -0
- package/hooks/intercept.js +50 -0
- package/lib/config-utils.js +51 -1
- package/lib/config.js +12 -0
- package/package.json +1 -1
|
@@ -74,9 +74,16 @@ function main() {
|
|
|
74
74
|
|
|
75
75
|
config.settings = config.settings || {};
|
|
76
76
|
config.settings.preferred_provider = requested;
|
|
77
|
+
if (requested !== 'auto') {
|
|
78
|
+
delete config.settings.preferred_model;
|
|
79
|
+
delete config.settings.preferredModel;
|
|
80
|
+
}
|
|
77
81
|
if (!saveConfig(config)) { process.exit(1); }
|
|
78
82
|
|
|
79
83
|
console.log(`Provider: ${current.value} → ${requested}`);
|
|
84
|
+
if (requested !== 'auto') {
|
|
85
|
+
console.log(' Cleared preferred_model to keep provider/model force hints mutually exclusive.');
|
|
86
|
+
}
|
|
80
87
|
console.log(` ${DESC[requested]}`);
|
|
81
88
|
console.log(' Takes effect on next request.');
|
|
82
89
|
}
|
|
@@ -127,6 +127,10 @@ function setDimension(dimension, value, config) {
|
|
|
127
127
|
|
|
128
128
|
config.settings = config.settings || {};
|
|
129
129
|
config.settings[configKey] = resolved;
|
|
130
|
+
if (configKey === 'preferred_provider' && resolved !== 'auto') {
|
|
131
|
+
delete config.settings.preferred_model;
|
|
132
|
+
delete config.settings.preferredModel;
|
|
133
|
+
}
|
|
130
134
|
if (configKeyAlt && config.settings[configKeyAlt]) {
|
|
131
135
|
delete config.settings[configKeyAlt];
|
|
132
136
|
}
|
|
@@ -134,6 +138,9 @@ function setDimension(dimension, value, config) {
|
|
|
134
138
|
if (!saveConfig(config)) { process.exit(1); }
|
|
135
139
|
|
|
136
140
|
console.log(`${label} updated: ${current.value} → ${resolved}`);
|
|
141
|
+
if (configKey === 'preferred_provider' && resolved !== 'auto') {
|
|
142
|
+
console.log(' Cleared preferred_model to keep provider/model force hints mutually exclusive.');
|
|
143
|
+
}
|
|
137
144
|
console.log(` ${descMap[resolved]}`);
|
|
138
145
|
console.log(` Takes effect on next request.`);
|
|
139
146
|
}
|
package/hooks/intercept.js
CHANGED
|
@@ -54,6 +54,8 @@ const VALID_PROVIDER_HINTS = new Set([
|
|
|
54
54
|
'cohere'
|
|
55
55
|
]);
|
|
56
56
|
|
|
57
|
+
const DISABLED_MODEL_HINTS = new Set(['auto', 'none', 'off']);
|
|
58
|
+
|
|
57
59
|
function normalizeOrchestrationMode(mode) {
|
|
58
60
|
if (typeof mode !== 'string') {
|
|
59
61
|
return null;
|
|
@@ -120,6 +122,42 @@ function resolvePreferredProvider(settings) {
|
|
|
120
122
|
return cfgProvider || 'auto';
|
|
121
123
|
}
|
|
122
124
|
|
|
125
|
+
function normalizePreferredModel(model) {
|
|
126
|
+
if (typeof model !== 'string') {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
const trimmed = model.trim();
|
|
130
|
+
if (!trimmed) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
if (DISABLED_MODEL_HINTS.has(trimmed.toLowerCase())) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
return trimmed;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function resolvePreferredModel(settings) {
|
|
140
|
+
const envModel = normalizePreferredModel(
|
|
141
|
+
process.env.PLEXOR_MODEL || process.env.PLEXOR_PREFERRED_MODEL
|
|
142
|
+
);
|
|
143
|
+
if (envModel) {
|
|
144
|
+
return envModel;
|
|
145
|
+
}
|
|
146
|
+
const cfgModel = normalizePreferredModel(settings?.preferredModel || settings?.preferred_model);
|
|
147
|
+
return cfgModel || null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function validateForceHintSelection(preferredProvider, preferredModel) {
|
|
151
|
+
if (!preferredModel || preferredProvider === 'auto') {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const error = new Error(
|
|
155
|
+
'Invalid Plexor config: force only one hint. Set preferred_provider OR preferred_model, not both.'
|
|
156
|
+
);
|
|
157
|
+
error.code = 'PLEXOR_CONFIG_CONFLICT';
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
|
|
123
161
|
// Try to load lib modules, fall back to inline implementations
|
|
124
162
|
let ConfigManager, SessionManager, LocalCache, Logger, PlexorClient;
|
|
125
163
|
let config, session, cache, logger;
|
|
@@ -175,6 +213,7 @@ try {
|
|
|
175
213
|
localCacheEnabled: cfg.settings?.localCacheEnabled ?? false,
|
|
176
214
|
mode: cfg.settings?.mode || 'balanced',
|
|
177
215
|
preferredProvider: cfg.settings?.preferred_provider || 'auto',
|
|
216
|
+
preferredModel: cfg.settings?.preferredModel || cfg.settings?.preferred_model || null,
|
|
178
217
|
orchestrationMode:
|
|
179
218
|
cfg.settings?.orchestrationMode || cfg.settings?.orchestration_mode || 'autonomous'
|
|
180
219
|
};
|
|
@@ -298,6 +337,8 @@ async function main() {
|
|
|
298
337
|
const orchestrationMode = resolveOrchestrationMode(settings);
|
|
299
338
|
const gatewayMode = resolveGatewayMode(settings);
|
|
300
339
|
const preferredProvider = resolvePreferredProvider(settings);
|
|
340
|
+
const preferredModel = resolvePreferredModel(settings);
|
|
341
|
+
validateForceHintSelection(preferredProvider, preferredModel);
|
|
301
342
|
|
|
302
343
|
// Phase 3 Hypervisor Mode Detection
|
|
303
344
|
// When ANTHROPIC_BASE_URL points to Plexor, all intelligence is server-side
|
|
@@ -316,6 +357,7 @@ async function main() {
|
|
|
316
357
|
// Add session tracking metadata (server will use this for analytics)
|
|
317
358
|
return output({
|
|
318
359
|
...request,
|
|
360
|
+
...(preferredModel ? { model: preferredModel } : {}),
|
|
319
361
|
plexor_mode: gatewayMode,
|
|
320
362
|
...(preferredProvider !== 'auto' ? { plexor_provider: preferredProvider } : {}),
|
|
321
363
|
plexor_orchestration_mode: orchestrationMode,
|
|
@@ -326,6 +368,7 @@ async function main() {
|
|
|
326
368
|
orchestration_mode: orchestrationMode,
|
|
327
369
|
plexor_mode: gatewayMode,
|
|
328
370
|
preferred_provider: preferredProvider,
|
|
371
|
+
preferred_model: preferredModel,
|
|
329
372
|
cwd: process.cwd(),
|
|
330
373
|
timestamp: Date.now(),
|
|
331
374
|
}
|
|
@@ -488,6 +531,13 @@ async function main() {
|
|
|
488
531
|
return output(optimizedRequest);
|
|
489
532
|
|
|
490
533
|
} catch (error) {
|
|
534
|
+
if (error?.code === 'PLEXOR_CONFIG_CONFLICT') {
|
|
535
|
+
logger.error(`Configuration error: ${error.message}`);
|
|
536
|
+
logger.ux(error.message);
|
|
537
|
+
process.stderr.write(`\n[Plexor] ${error.message}\n`);
|
|
538
|
+
process.exit(1);
|
|
539
|
+
}
|
|
540
|
+
|
|
491
541
|
logger.error(`Error: ${error.message}`);
|
|
492
542
|
logger.ux(`Optimization hook error: ${error.message}`);
|
|
493
543
|
logger.debug(error.stack);
|
package/lib/config-utils.js
CHANGED
|
@@ -7,6 +7,50 @@ const path = require('path');
|
|
|
7
7
|
const crypto = require('crypto');
|
|
8
8
|
const { PLEXOR_DIR, CONFIG_PATH } = require('./constants');
|
|
9
9
|
|
|
10
|
+
const DISABLED_HINT_VALUES = new Set(['', 'auto', 'none', 'off']);
|
|
11
|
+
|
|
12
|
+
function normalizeForcedProvider(value) {
|
|
13
|
+
if (typeof value !== 'string') {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const normalized = value.trim().toLowerCase();
|
|
17
|
+
if (!normalized || normalized === 'auto') {
|
|
18
|
+
return 'auto';
|
|
19
|
+
}
|
|
20
|
+
return normalized;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function normalizeForcedModel(value) {
|
|
24
|
+
if (typeof value !== 'string') {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const normalized = value.trim();
|
|
28
|
+
if (!normalized || DISABLED_HINT_VALUES.has(normalized.toLowerCase())) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return normalized;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function hasForcedHintConflict(config) {
|
|
35
|
+
const settings = config?.settings || {};
|
|
36
|
+
const provider = normalizeForcedProvider(
|
|
37
|
+
settings.preferred_provider ?? settings.preferredProvider ?? 'auto'
|
|
38
|
+
);
|
|
39
|
+
const model = normalizeForcedModel(settings.preferred_model ?? settings.preferredModel);
|
|
40
|
+
return Boolean(model) && provider !== 'auto';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function validateForcedHintConfig(config) {
|
|
44
|
+
if (!hasForcedHintConflict(config)) {
|
|
45
|
+
return { ok: true };
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
ok: false,
|
|
49
|
+
message:
|
|
50
|
+
'Invalid Plexor config: set only one force hint. Use preferred_provider OR preferred_model, not both.'
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
10
54
|
function loadConfig() {
|
|
11
55
|
try {
|
|
12
56
|
if (!fs.existsSync(CONFIG_PATH)) {
|
|
@@ -31,6 +75,12 @@ function loadConfig() {
|
|
|
31
75
|
|
|
32
76
|
function saveConfig(config) {
|
|
33
77
|
try {
|
|
78
|
+
const validation = validateForcedHintConfig(config);
|
|
79
|
+
if (!validation.ok) {
|
|
80
|
+
console.error(`Error: ${validation.message}`);
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
|
|
34
84
|
if (!fs.existsSync(PLEXOR_DIR)) {
|
|
35
85
|
fs.mkdirSync(PLEXOR_DIR, { recursive: true, mode: 0o700 });
|
|
36
86
|
}
|
|
@@ -71,4 +121,4 @@ function readSetting(config, configKey, configKeyAlt, envVar, validValues, defau
|
|
|
71
121
|
return { value: defaultValue, source: 'default' };
|
|
72
122
|
}
|
|
73
123
|
|
|
74
|
-
module.exports = { loadConfig, saveConfig, readSetting };
|
|
124
|
+
module.exports = { loadConfig, saveConfig, readSetting, hasForcedHintConflict, validateForcedHintConfig };
|
package/lib/config.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
const fs = require('fs');
|
|
6
6
|
const path = require('path');
|
|
7
7
|
const { CONFIG_PATH, PLEXOR_DIR, DEFAULT_API_URL, DEFAULT_TIMEOUT } = require('./constants');
|
|
8
|
+
const { validateForcedHintConfig } = require('./config-utils');
|
|
8
9
|
|
|
9
10
|
class ConfigManager {
|
|
10
11
|
constructor() {
|
|
@@ -23,6 +24,7 @@ class ConfigManager {
|
|
|
23
24
|
localCacheEnabled: cfg.settings?.localCacheEnabled ?? false,
|
|
24
25
|
mode: cfg.settings?.mode || 'balanced',
|
|
25
26
|
preferredProvider: cfg.settings?.preferred_provider || 'auto',
|
|
27
|
+
preferredModel: cfg.settings?.preferredModel || cfg.settings?.preferred_model || null,
|
|
26
28
|
orchestrationMode:
|
|
27
29
|
cfg.settings?.orchestrationMode || cfg.settings?.orchestration_mode || 'autonomous'
|
|
28
30
|
};
|
|
@@ -55,6 +57,11 @@ class ConfigManager {
|
|
|
55
57
|
localCacheEnabled: config.localCacheEnabled ?? existing.settings?.localCacheEnabled,
|
|
56
58
|
mode: config.mode ?? existing.settings?.mode,
|
|
57
59
|
preferred_provider: config.preferredProvider ?? existing.settings?.preferred_provider,
|
|
60
|
+
preferred_model:
|
|
61
|
+
config.preferredModel ??
|
|
62
|
+
config.preferred_model ??
|
|
63
|
+
existing.settings?.preferredModel ??
|
|
64
|
+
existing.settings?.preferred_model,
|
|
58
65
|
orchestrationMode:
|
|
59
66
|
config.orchestrationMode ??
|
|
60
67
|
config.orchestration_mode ??
|
|
@@ -63,6 +70,11 @@ class ConfigManager {
|
|
|
63
70
|
}
|
|
64
71
|
};
|
|
65
72
|
|
|
73
|
+
const validation = validateForcedHintConfig(updated);
|
|
74
|
+
if (!validation.ok) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
|
|
66
78
|
fs.writeFileSync(this.configPath, JSON.stringify(updated, null, 2), { mode: 0o600 });
|
|
67
79
|
return true;
|
|
68
80
|
} catch {
|
package/package.json
CHANGED