coding-tool-x 3.7.10 → 3.7.12
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/CHANGELOG.md +3 -0
- package/README.md +1 -1
- package/dist/web/assets/{Analytics-CkUtnoz9.js → Analytics-8dRv1aYW.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-BwPqhE-N.js → ConfigTemplates-BQRXSICO.js} +1 -1
- package/dist/web/assets/Home-BtzWhKIa.js +1 -0
- package/dist/web/assets/Home-DYVy4cGZ.css +1 -0
- package/dist/web/assets/{PluginManager-JMXWl37b.js → PluginManager-BTa-Ygf6.js} +1 -1
- package/dist/web/assets/{ProjectList-CZwDgVvt.js → ProjectList-F_cB8ldA.js} +1 -1
- package/dist/web/assets/{SessionList-2fZmN7Au.js → SessionList-LOrbPQvu.js} +1 -1
- package/dist/web/assets/SkillManager-BsX8Qpj0.css +1 -0
- package/dist/web/assets/SkillManager-BzI_t-yV.js +1 -0
- package/dist/web/assets/{WorkspaceManager-B3lhhBD0.js → WorkspaceManager-Db9RGiz7.js} +1 -1
- package/dist/web/assets/index-DIWJmyL6.js +2 -0
- package/dist/web/assets/{index-C5nLTbOk.css → index-bJRG3RXH.css} +1 -1
- package/dist/web/index.html +2 -2
- package/docs/superpowers/plans/2026-08-01-omp-skill-scan-settings.md +759 -0
- package/docs/superpowers/specs/2026-08-01-omp-skill-scan-settings-design.md +224 -0
- package/package.json +1 -1
- package/src/commands/proxy-control.js +12 -12
- package/src/commands/toggle-proxy.js +16 -17
- package/src/commands/ui.js +11 -1
- package/src/config/default.js +1 -1
- package/src/config/paths.js +52 -29
- package/src/index.js +42 -16
- package/src/server/api/omp-channels.js +6 -4
- package/src/server/api/omp-config.js +1 -1
- package/src/server/api/omp-proxy.js +13 -42
- package/src/server/api/plugins.js +119 -47
- package/src/server/api/skills.js +63 -10
- package/src/server/index.js +3 -3
- package/src/server/omp-proxy-server.js +142 -10
- package/src/server/services/channel-scheduler.js +59 -9
- package/src/server/services/model-definition-schema.js +2 -1
- package/src/server/services/omp-auth-gateway-client.js +62 -0
- package/src/server/services/omp-channels.js +168 -12
- package/src/server/services/omp-config.js +71 -6
- package/src/server/services/omp-gateway-routing.js +295 -0
- package/src/server/services/omp-gateway.js +919 -0
- package/src/server/services/omp-native-plugin-adapter.js +456 -0
- package/src/server/services/omp-session-log-observer.js +138 -0
- package/src/server/services/omp-sessions.js +80 -0
- package/src/server/services/omp-settings-manager.js +338 -87
- package/src/server/services/omp-skill-discovery.js +358 -0
- package/src/server/services/omp-skill-settings-service.js +97 -0
- package/src/server/services/pi-omp-migration.js +273 -0
- package/src/server/services/platform-resolution.js +44 -0
- package/src/server/services/plugins-service.js +85 -561
- package/src/server/services/project-path-validation.js +65 -0
- package/src/server/services/skill-service.js +169 -77
- package/dist/web/assets/Home-BANl91zG.js +0 -1
- package/dist/web/assets/Home-CqnBXFxj.css +0 -1
- package/dist/web/assets/SkillManager-Bhzhkeis.js +0 -1
- package/dist/web/assets/SkillManager-D7pd-d_P.css +0 -1
- package/dist/web/assets/index-LYvv7wtx.js +0 -2
|
@@ -3,6 +3,7 @@ const path = require('path');
|
|
|
3
3
|
const { spawnSync } = require('child_process');
|
|
4
4
|
const yaml = require('js-yaml');
|
|
5
5
|
const ompConfig = require('./omp-config');
|
|
6
|
+
const { prepareManagedOmpChannels } = require('./omp-gateway-routing');
|
|
6
7
|
const { MODEL_METADATA, MODEL_ALIASES } = require('../../config/model-metadata');
|
|
7
8
|
const {
|
|
8
9
|
MODEL_METADATA_MODES,
|
|
@@ -15,7 +16,7 @@ const {
|
|
|
15
16
|
|
|
16
17
|
const MANAGED_PROVIDER_PREFIX = 'ctx-';
|
|
17
18
|
const MODELS_BACKUP_MARKER = '.ctx-backup-';
|
|
18
|
-
const VISIBILITY_STATE_VERSION =
|
|
19
|
+
const VISIBILITY_STATE_VERSION = 2;
|
|
19
20
|
const MANAGED_VISIBILITY_STATE_FILE = 'coding-tool-x-omp-managed-visibility.json';
|
|
20
21
|
const NO_MANAGED_MODELS_SELECTOR = `${MANAGED_PROVIDER_PREFIX}coding-tool-x/__no_models_configured__`;
|
|
21
22
|
let lastManagedOmpSyncResult = null;
|
|
@@ -45,6 +46,12 @@ function normalizeProviderId(value = '') {
|
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
function getManagedProviderId(channel = {}) {
|
|
49
|
+
const explicitId = normalizeProviderId(channel.managedProviderId || '');
|
|
50
|
+
if (channel.managedProviderId) {
|
|
51
|
+
return explicitId.startsWith(MANAGED_PROVIDER_PREFIX)
|
|
52
|
+
? explicitId
|
|
53
|
+
: `${MANAGED_PROVIDER_PREFIX}${explicitId}`;
|
|
54
|
+
}
|
|
48
55
|
const baseId = normalizeProviderId(channel.providerKey || channel.provider || channel.name || channel.id);
|
|
49
56
|
return baseId.startsWith(MANAGED_PROVIDER_PREFIX) ? baseId : `${MANAGED_PROVIDER_PREFIX}${baseId}`;
|
|
50
57
|
}
|
|
@@ -116,6 +123,49 @@ function getOwnProperty(object, key) {
|
|
|
116
123
|
: false;
|
|
117
124
|
}
|
|
118
125
|
|
|
126
|
+
function cloneJson(value) {
|
|
127
|
+
if (value === undefined) return undefined;
|
|
128
|
+
return JSON.parse(JSON.stringify(value));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function captureFileSnapshots(filePaths = []) {
|
|
132
|
+
return filePaths.map((filePath) => ({
|
|
133
|
+
filePath,
|
|
134
|
+
existed: Boolean(filePath && fs.existsSync(filePath)),
|
|
135
|
+
content: filePath && fs.existsSync(filePath) ? fs.readFileSync(filePath) : null
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function restoreFileSnapshots(snapshots = []) {
|
|
140
|
+
snapshots.forEach((snapshot) => {
|
|
141
|
+
if (!snapshot.filePath) return;
|
|
142
|
+
if (snapshot.existed) {
|
|
143
|
+
ensureOmpDir(path.dirname(snapshot.filePath));
|
|
144
|
+
writeFileAtomic(snapshot.filePath, snapshot.content);
|
|
145
|
+
} else if (fs.existsSync(snapshot.filePath)) {
|
|
146
|
+
fs.unlinkSync(snapshot.filePath);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function writeFileAtomic(filePath, content) {
|
|
152
|
+
ensureOmpDir(path.dirname(filePath));
|
|
153
|
+
const temporaryPath = `${filePath}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
154
|
+
const mode = fs.existsSync(filePath)
|
|
155
|
+
? fs.statSync(filePath).mode & 0o777
|
|
156
|
+
: 0o600;
|
|
157
|
+
try {
|
|
158
|
+
fs.writeFileSync(temporaryPath, content, { mode });
|
|
159
|
+
fs.chmodSync(temporaryPath, mode);
|
|
160
|
+
fs.renameSync(temporaryPath, filePath);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
if (fs.existsSync(temporaryPath)) {
|
|
163
|
+
fs.unlinkSync(temporaryPath);
|
|
164
|
+
}
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
119
169
|
function normalizeModels(channel = {}, options = {}) {
|
|
120
170
|
const models = [];
|
|
121
171
|
const catalogIndex = options.catalogIndex instanceof Map ? options.catalogIndex : new Map();
|
|
@@ -170,7 +220,9 @@ function normalizeModels(channel = {}, options = {}) {
|
|
|
170
220
|
}
|
|
171
221
|
|
|
172
222
|
function readOmpCatalogModels(command, providerId, options = {}) {
|
|
173
|
-
const requestedModelIds = uniqueStrings(options.requestedModelIds)
|
|
223
|
+
const requestedModelIds = uniqueStrings(options.requestedModelIds)
|
|
224
|
+
.map(modelId => splitModelSelector(modelId).modelId)
|
|
225
|
+
.filter(Boolean);
|
|
174
226
|
const requested = new Set(requestedModelIds.map(modelId => modelId.toLowerCase()));
|
|
175
227
|
const useFullCatalog = requested.size > 0;
|
|
176
228
|
const cacheKey = `${command}\u0000${useFullCatalog ? `requested:${providerId}:${[...requested].sort().join(',')}` : providerId}`;
|
|
@@ -277,13 +329,32 @@ function buildProviderEntry(channel = {}, options = {}) {
|
|
|
277
329
|
const providerName = channel.providerKey || channel.provider || channel.name || channel.id || 'provider';
|
|
278
330
|
options.warnings.push(...normalizedProvider.warnings.map(message => `${providerName}: ${message}`));
|
|
279
331
|
}
|
|
332
|
+
let models = normalizeModels(channel, { catalogIndex, warnings: options.warnings });
|
|
333
|
+
if (channel._ompGatewayRoute) {
|
|
334
|
+
models = models.map((model) => {
|
|
335
|
+
const sanitized = { ...model };
|
|
336
|
+
delete sanitized.baseUrl;
|
|
337
|
+
delete sanitized.headers;
|
|
338
|
+
return sanitized;
|
|
339
|
+
});
|
|
340
|
+
}
|
|
280
341
|
const entry = compactObject({
|
|
281
342
|
...normalizedProvider.config,
|
|
282
343
|
baseUrl: String(channel.baseUrl || providerConfig.baseUrl || '').trim(),
|
|
283
344
|
api: normalizeProviderApi(channel.providerApi || channel.api || channel.wireApi || providerConfig.api),
|
|
284
|
-
models
|
|
345
|
+
models
|
|
285
346
|
});
|
|
286
347
|
|
|
348
|
+
if (channel._ompGatewayRoute) {
|
|
349
|
+
delete entry.headers;
|
|
350
|
+
delete entry.apiKey;
|
|
351
|
+
if (channel.authMode === 'none') {
|
|
352
|
+
entry.auth = 'none';
|
|
353
|
+
} else {
|
|
354
|
+
delete entry.auth;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
287
358
|
const apiKey = String(channel.apiKey || providerConfig.apiKey || '').trim();
|
|
288
359
|
if (apiKey) {
|
|
289
360
|
entry.apiKey = apiKey;
|
|
@@ -321,7 +392,7 @@ function writeModelsConfig(config, filePath = getOmpPaths().modelsYml) {
|
|
|
321
392
|
noRefs: true,
|
|
322
393
|
sortKeys: false
|
|
323
394
|
});
|
|
324
|
-
|
|
395
|
+
writeFileAtomic(filePath, doc);
|
|
325
396
|
}
|
|
326
397
|
|
|
327
398
|
function getOmpSettingsPath(paths = getOmpPaths()) {
|
|
@@ -359,7 +430,7 @@ function writeOmpSettingsConfig(config, filePath = getOmpSettingsPath()) {
|
|
|
359
430
|
noRefs: true,
|
|
360
431
|
sortKeys: false
|
|
361
432
|
});
|
|
362
|
-
|
|
433
|
+
writeFileAtomic(filePath, doc);
|
|
363
434
|
}
|
|
364
435
|
|
|
365
436
|
function getModelsBackupPrefix(filePath) {
|
|
@@ -420,7 +491,7 @@ function readManagedVisibilityState(paths = getOmpPaths()) {
|
|
|
420
491
|
function writeManagedVisibilityState(state, paths = getOmpPaths()) {
|
|
421
492
|
const filePath = getManagedVisibilityStatePath(paths);
|
|
422
493
|
ensureOmpDir(path.dirname(filePath));
|
|
423
|
-
|
|
494
|
+
writeFileAtomic(filePath, `${JSON.stringify(state, null, 2)}\n`);
|
|
424
495
|
return filePath;
|
|
425
496
|
}
|
|
426
497
|
|
|
@@ -602,6 +673,9 @@ function buildManagedModelsConfig(channels = [], baseConfig = readModelsConfig()
|
|
|
602
673
|
}
|
|
603
674
|
|
|
604
675
|
function getOriginalProviderId(channel = {}) {
|
|
676
|
+
if (channel.originalProviderId) {
|
|
677
|
+
return normalizeProviderId(channel.originalProviderId);
|
|
678
|
+
}
|
|
605
679
|
const providerId = normalizeProviderId(channel.providerKey || channel.provider || channel.name || channel.id);
|
|
606
680
|
return isManagedProviderId(providerId)
|
|
607
681
|
? providerId.slice(MANAGED_PROVIDER_PREFIX.length)
|
|
@@ -679,11 +753,18 @@ function captureOriginalVisibility(settings = {}) {
|
|
|
679
753
|
const modelRoles = settings.modelRoles && typeof settings.modelRoles === 'object' && !Array.isArray(settings.modelRoles)
|
|
680
754
|
? settings.modelRoles
|
|
681
755
|
: {};
|
|
756
|
+
const fallbackChains = settings.retry && typeof settings.retry === 'object' && !Array.isArray(settings.retry)
|
|
757
|
+
? settings.retry.fallbackChains
|
|
758
|
+
: undefined;
|
|
682
759
|
return {
|
|
683
760
|
enabledModels: getOwnProperty(settings, 'enabledModels') ? uniqueStrings(settings.enabledModels) : null,
|
|
684
761
|
disabledProviders: getOwnProperty(settings, 'disabledProviders') ? uniqueStrings(settings.disabledProviders) : null,
|
|
685
762
|
modelRolesHadDefault: getOwnProperty(modelRoles, 'default'),
|
|
686
|
-
modelRolesDefault: getOwnProperty(modelRoles, 'default') ? String(modelRoles.default || '') : null
|
|
763
|
+
modelRolesDefault: getOwnProperty(modelRoles, 'default') ? String(modelRoles.default || '') : null,
|
|
764
|
+
modelRolesHadValue: getOwnProperty(settings, 'modelRoles'),
|
|
765
|
+
modelRoles: getOwnProperty(settings, 'modelRoles') ? cloneJson(modelRoles) : null,
|
|
766
|
+
retryFallbackChainsHadValue: fallbackChains !== undefined,
|
|
767
|
+
retryFallbackChains: fallbackChains !== undefined ? cloneJson(fallbackChains) : null
|
|
687
768
|
};
|
|
688
769
|
}
|
|
689
770
|
|
|
@@ -701,22 +782,86 @@ function collectUserDisabledProviders(settings = {}, previousState = null) {
|
|
|
701
782
|
return uniqueStrings([...originalDisabled, ...userAddedDuringManagedMode]);
|
|
702
783
|
}
|
|
703
784
|
|
|
704
|
-
function
|
|
705
|
-
const
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
785
|
+
function buildProviderMappings(channels = []) {
|
|
786
|
+
const originalToManaged = {};
|
|
787
|
+
const managedToOriginal = {};
|
|
788
|
+
channels.forEach((channel) => {
|
|
789
|
+
const original = getOriginalProviderId(channel);
|
|
790
|
+
const managed = getManagedProviderId(channel);
|
|
791
|
+
if (!original || !managed) return;
|
|
792
|
+
if (!originalToManaged[original]) {
|
|
793
|
+
originalToManaged[original] = managed;
|
|
794
|
+
}
|
|
795
|
+
managedToOriginal[managed] = original;
|
|
796
|
+
});
|
|
797
|
+
return { originalToManaged, managedToOriginal };
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
function rewriteModelSelector(value, providerMap = {}) {
|
|
801
|
+
if (typeof value !== 'string') return value;
|
|
802
|
+
const index = value.indexOf('/');
|
|
803
|
+
if (index <= 0) return value;
|
|
804
|
+
const providerId = value.slice(0, index);
|
|
805
|
+
const replacement = providerMap[providerId];
|
|
806
|
+
return replacement ? `${replacement}${value.slice(index)}` : value;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
function rewriteSelectorTree(value, providerMap = {}) {
|
|
810
|
+
if (typeof value === 'string') return rewriteModelSelector(value, providerMap);
|
|
811
|
+
if (Array.isArray(value)) return value.map(item => rewriteSelectorTree(item, providerMap));
|
|
812
|
+
if (value && typeof value === 'object') {
|
|
813
|
+
return Object.fromEntries(
|
|
814
|
+
Object.entries(value).map(([key, item]) => [key, rewriteSelectorTree(item, providerMap)])
|
|
815
|
+
);
|
|
816
|
+
}
|
|
817
|
+
return value;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
function removeManagedSelectorTree(value) {
|
|
821
|
+
if (typeof value === 'string') {
|
|
822
|
+
const providerId = String(value).split('/')[0];
|
|
823
|
+
return isManagedProviderId(providerId) ? undefined : value;
|
|
824
|
+
}
|
|
825
|
+
if (Array.isArray(value)) {
|
|
826
|
+
return value
|
|
827
|
+
.map(removeManagedSelectorTree)
|
|
828
|
+
.filter(item => item !== undefined);
|
|
829
|
+
}
|
|
830
|
+
if (value && typeof value === 'object') {
|
|
831
|
+
return Object.fromEntries(
|
|
832
|
+
Object.entries(value)
|
|
833
|
+
.map(([key, item]) => [key, removeManagedSelectorTree(item)])
|
|
834
|
+
.filter(([, item]) => item !== undefined)
|
|
835
|
+
);
|
|
712
836
|
}
|
|
713
|
-
|
|
714
|
-
|
|
837
|
+
return value;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
function applyManagedModelRoles(settings, visibility, mappings, previousState = null) {
|
|
841
|
+
const originalRoles = previousState?.active && previousState.original?.modelRolesHadValue
|
|
842
|
+
? previousState.original.modelRoles
|
|
843
|
+
: settings.modelRoles;
|
|
844
|
+
const roles = originalRoles && typeof originalRoles === 'object' && !Array.isArray(originalRoles)
|
|
845
|
+
? rewriteSelectorTree(cloneJson(originalRoles), mappings.originalToManaged)
|
|
846
|
+
: {};
|
|
847
|
+
const originalDefault = String(originalRoles?.default || '');
|
|
848
|
+
const mappedDefault = rewriteModelSelector(originalDefault, mappings.originalToManaged);
|
|
849
|
+
const defaultWasMapped = originalDefault && mappedDefault !== originalDefault;
|
|
850
|
+
const defaultIsManaged = isManagedProviderId(String(roles.default || '').split('/')[0]);
|
|
851
|
+
if (visibility.managedDefaultModel && (!roles.default || (!defaultWasMapped && !defaultIsManaged))) {
|
|
715
852
|
roles.default = visibility.managedDefaultModel;
|
|
716
853
|
}
|
|
717
854
|
return roles;
|
|
718
855
|
}
|
|
719
856
|
|
|
857
|
+
function applyManagedFallbackChains(settings, mappings, previousState = null) {
|
|
858
|
+
const source = previousState?.active && previousState.original?.retryFallbackChainsHadValue
|
|
859
|
+
? previousState.original.retryFallbackChains
|
|
860
|
+
: settings.retry?.fallbackChains;
|
|
861
|
+
if (source === undefined) return undefined;
|
|
862
|
+
return rewriteSelectorTree(cloneJson(source), mappings.originalToManaged);
|
|
863
|
+
}
|
|
864
|
+
|
|
720
865
|
function syncManagedOmpVisibility(channels = [], modelsConfig = { providers: {} }, options = {}) {
|
|
721
866
|
const paths = getOmpPaths();
|
|
722
867
|
const settingsPath = getOmpSettingsPath(paths);
|
|
@@ -724,6 +869,7 @@ function syncManagedOmpVisibility(channels = [], modelsConfig = { providers: {}
|
|
|
724
869
|
const settings = readOmpSettingsConfig(settingsPath);
|
|
725
870
|
const previousState = readManagedVisibilityState(paths);
|
|
726
871
|
const visibility = collectManagedVisibility(channels, modelsConfig, options);
|
|
872
|
+
const mappings = buildProviderMappings(channels);
|
|
727
873
|
const original = previousState?.active && previousState.original
|
|
728
874
|
? previousState.original
|
|
729
875
|
: captureOriginalVisibility(settings);
|
|
@@ -735,7 +881,13 @@ function syncManagedOmpVisibility(channels = [], modelsConfig = { providers: {}
|
|
|
735
881
|
...collectUserDisabledProviders(settings, previousState),
|
|
736
882
|
...visibility.managedDisabledProviders
|
|
737
883
|
]);
|
|
738
|
-
settings.modelRoles =
|
|
884
|
+
settings.modelRoles = applyManagedModelRoles(settings, visibility, mappings, previousState);
|
|
885
|
+
const fallbackChains = applyManagedFallbackChains(settings, mappings, previousState);
|
|
886
|
+
if (fallbackChains !== undefined) {
|
|
887
|
+
settings.retry = settings.retry && typeof settings.retry === 'object' && !Array.isArray(settings.retry)
|
|
888
|
+
? { ...settings.retry, fallbackChains }
|
|
889
|
+
: { fallbackChains };
|
|
890
|
+
}
|
|
739
891
|
|
|
740
892
|
const after = JSON.stringify(settings);
|
|
741
893
|
if (before !== after) {
|
|
@@ -750,7 +902,12 @@ function syncManagedOmpVisibility(channels = [], modelsConfig = { providers: {}
|
|
|
750
902
|
managedEnabledModelsForSettings: visibility.managedEnabledModelsForSettings,
|
|
751
903
|
managedDisabledProviders: visibility.managedDisabledProviders,
|
|
752
904
|
managedDefaultModel: visibility.managedDefaultModel,
|
|
905
|
+
providerMappings: mappings,
|
|
753
906
|
original,
|
|
907
|
+
applied: {
|
|
908
|
+
modelRoles: cloneJson(settings.modelRoles),
|
|
909
|
+
retryFallbackChains: cloneJson(settings.retry?.fallbackChains)
|
|
910
|
+
},
|
|
754
911
|
updatedAt: new Date().toISOString()
|
|
755
912
|
};
|
|
756
913
|
writeManagedVisibilityState(state, paths);
|
|
@@ -819,7 +976,39 @@ function removeManagedOmpVisibility(options = {}) {
|
|
|
819
976
|
warnings.push('OMP disabledProviders was changed while coding-tool-x managed visibility was active; removed only managed provider entries.');
|
|
820
977
|
}
|
|
821
978
|
|
|
822
|
-
if (
|
|
979
|
+
if (state.version >= 2 && state.original) {
|
|
980
|
+
const currentRoles = settings.modelRoles && typeof settings.modelRoles === 'object' && !Array.isArray(settings.modelRoles)
|
|
981
|
+
? settings.modelRoles
|
|
982
|
+
: undefined;
|
|
983
|
+
if (JSON.stringify(currentRoles) === JSON.stringify(state.applied?.modelRoles)) {
|
|
984
|
+
if (state.original.modelRolesHadValue) {
|
|
985
|
+
settings.modelRoles = cloneJson(state.original.modelRoles);
|
|
986
|
+
} else {
|
|
987
|
+
delete settings.modelRoles;
|
|
988
|
+
}
|
|
989
|
+
} else if (currentRoles) {
|
|
990
|
+
settings.modelRoles = rewriteSelectorTree(currentRoles, state.providerMappings?.managedToOriginal || {});
|
|
991
|
+
warnings.push('OMP modelRoles was changed while coding-tool-x managed visibility was active; restored managed provider references only.');
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
const currentFallback = settings.retry?.fallbackChains;
|
|
995
|
+
if (JSON.stringify(currentFallback) === JSON.stringify(state.applied?.retryFallbackChains)) {
|
|
996
|
+
if (state.original.retryFallbackChainsHadValue) {
|
|
997
|
+
settings.retry = settings.retry && typeof settings.retry === 'object' && !Array.isArray(settings.retry)
|
|
998
|
+
? { ...settings.retry, fallbackChains: cloneJson(state.original.retryFallbackChains) }
|
|
999
|
+
: { fallbackChains: cloneJson(state.original.retryFallbackChains) };
|
|
1000
|
+
} else if (settings.retry && typeof settings.retry === 'object' && !Array.isArray(settings.retry)) {
|
|
1001
|
+
delete settings.retry.fallbackChains;
|
|
1002
|
+
if (Object.keys(settings.retry).length === 0) delete settings.retry;
|
|
1003
|
+
}
|
|
1004
|
+
} else if (currentFallback !== undefined) {
|
|
1005
|
+
settings.retry.fallbackChains = rewriteSelectorTree(
|
|
1006
|
+
currentFallback,
|
|
1007
|
+
state.providerMappings?.managedToOriginal || {}
|
|
1008
|
+
);
|
|
1009
|
+
warnings.push('OMP retry.fallbackChains was changed while coding-tool-x managed visibility was active; restored managed provider references only.');
|
|
1010
|
+
}
|
|
1011
|
+
} else if (settings.modelRoles && typeof settings.modelRoles === 'object' && !Array.isArray(settings.modelRoles)) {
|
|
823
1012
|
const roles = { ...settings.modelRoles };
|
|
824
1013
|
if (roles.default === state.managedDefaultModel) {
|
|
825
1014
|
if (state.original?.modelRolesHadDefault) {
|
|
@@ -845,6 +1034,39 @@ function removeManagedOmpVisibility(options = {}) {
|
|
|
845
1034
|
}
|
|
846
1035
|
warnings.push('Removed stale coding-tool-x managed OMP enabledModels entries without a visibility state file.');
|
|
847
1036
|
}
|
|
1037
|
+
|
|
1038
|
+
if (settings.modelRoles && typeof settings.modelRoles === 'object' && !Array.isArray(settings.modelRoles)) {
|
|
1039
|
+
const roles = Object.fromEntries(
|
|
1040
|
+
Object.entries(settings.modelRoles).filter(([, model]) => {
|
|
1041
|
+
const providerId = String(model || '').split('/')[0];
|
|
1042
|
+
return !isManagedProviderId(providerId);
|
|
1043
|
+
})
|
|
1044
|
+
);
|
|
1045
|
+
if (Object.keys(roles).length !== Object.keys(settings.modelRoles).length) {
|
|
1046
|
+
settingsBackupPath = settingsBackupPath || createModelsBackupIfNeeded(settingsPath, options);
|
|
1047
|
+
if (Object.keys(roles).length > 0) {
|
|
1048
|
+
settings.modelRoles = roles;
|
|
1049
|
+
} else {
|
|
1050
|
+
delete settings.modelRoles;
|
|
1051
|
+
}
|
|
1052
|
+
warnings.push('Removed stale coding-tool-x managed OMP modelRoles entries without a visibility state file.');
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
const currentFallback = settings.retry?.fallbackChains;
|
|
1057
|
+
if (currentFallback !== undefined) {
|
|
1058
|
+
const fallbackChains = removeManagedSelectorTree(currentFallback);
|
|
1059
|
+
if (JSON.stringify(fallbackChains) !== JSON.stringify(currentFallback)) {
|
|
1060
|
+
settingsBackupPath = settingsBackupPath || createModelsBackupIfNeeded(settingsPath, options);
|
|
1061
|
+
if (fallbackChains && typeof fallbackChains === 'object' && Object.keys(fallbackChains).length > 0) {
|
|
1062
|
+
settings.retry.fallbackChains = fallbackChains;
|
|
1063
|
+
} else {
|
|
1064
|
+
delete settings.retry.fallbackChains;
|
|
1065
|
+
if (Object.keys(settings.retry).length === 0) delete settings.retry;
|
|
1066
|
+
}
|
|
1067
|
+
warnings.push('Removed stale coding-tool-x managed OMP retry.fallbackChains entries without a visibility state file.');
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
848
1070
|
}
|
|
849
1071
|
|
|
850
1072
|
const after = JSON.stringify(settings);
|
|
@@ -865,81 +1087,110 @@ function removeManagedOmpVisibility(options = {}) {
|
|
|
865
1087
|
|
|
866
1088
|
function writeManagedOmpProviders(channels = [], options = {}) {
|
|
867
1089
|
const paths = getOmpPaths();
|
|
1090
|
+
const settingsPath = getOmpSettingsPath(paths);
|
|
1091
|
+
const statePath = getManagedVisibilityStatePath(paths);
|
|
1092
|
+
const snapshots = captureFileSnapshots([paths.modelsYml, settingsPath, statePath]);
|
|
868
1093
|
const buildWarnings = [];
|
|
869
|
-
const
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
const
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
...(visibility.warnings || []),
|
|
882
|
-
...(validation.warnings || [])
|
|
883
|
-
];
|
|
884
|
-
recordManagedOmpSyncResult({
|
|
885
|
-
path: paths.modelsYml,
|
|
886
|
-
modelsPath: paths.modelsYml,
|
|
887
|
-
settingsPath: visibility.settingsPath,
|
|
888
|
-
statePath: visibility.statePath,
|
|
889
|
-
backupPath,
|
|
890
|
-
modelsBackupPath: backupPath,
|
|
891
|
-
settingsBackupPath: visibility.settingsBackupPath,
|
|
892
|
-
changed: true,
|
|
893
|
-
visibilityChanged: visibility.changed,
|
|
894
|
-
managedEnabledModels: visibility.managedEnabledModels,
|
|
895
|
-
managedEnabledModelsForSettings: visibility.managedEnabledModelsForSettings,
|
|
896
|
-
managedDisabledProviders: visibility.managedDisabledProviders,
|
|
897
|
-
managedDefaultModel: visibility.managedDefaultModel,
|
|
898
|
-
validation,
|
|
899
|
-
warnings
|
|
1094
|
+
const orderedChannels = options.activeChannelId
|
|
1095
|
+
? [
|
|
1096
|
+
...channels.filter(channel => channel?.id === options.activeChannelId),
|
|
1097
|
+
...channels.filter(channel => channel?.id !== options.activeChannelId)
|
|
1098
|
+
]
|
|
1099
|
+
: channels;
|
|
1100
|
+
const prepared = options.gateway
|
|
1101
|
+
? prepareManagedOmpChannels(orderedChannels, options.gateway)
|
|
1102
|
+
: { managedChannels: orderedChannels, unsupportedChannels: [] };
|
|
1103
|
+
const effectiveChannels = prepared.managedChannels;
|
|
1104
|
+
prepared.unsupportedChannels.forEach((channel) => {
|
|
1105
|
+
buildWarnings.push(`OMP channel "${channel.name || channel.id}" was not managed: ${channel.reason}.`);
|
|
900
1106
|
});
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
const config = readModelsConfig(paths.modelsYml);
|
|
908
|
-
const visibility = removeManagedOmpVisibility(options);
|
|
909
|
-
const before = Object.keys(config.providers || {}).length;
|
|
910
|
-
pruneManagedProviders(config.providers);
|
|
911
|
-
const after = Object.keys(config.providers || {}).length;
|
|
912
|
-
let backupPath = null;
|
|
913
|
-
let validation = {
|
|
914
|
-
skipped: true,
|
|
915
|
-
reason: before === after ? 'no-managed-providers' : 'not-run',
|
|
916
|
-
warnings: []
|
|
917
|
-
};
|
|
918
|
-
if (before !== after) {
|
|
919
|
-
backupPath = createModelsBackupIfNeeded(paths.modelsYml, options);
|
|
1107
|
+
try {
|
|
1108
|
+
const config = buildManagedModelsConfig(effectiveChannels, readModelsConfig(paths.modelsYml), {
|
|
1109
|
+
...options,
|
|
1110
|
+
warnings: buildWarnings
|
|
1111
|
+
});
|
|
1112
|
+
const backupPath = createModelsBackupIfNeeded(paths.modelsYml, options);
|
|
920
1113
|
writeModelsConfig(config, paths.modelsYml);
|
|
921
|
-
|
|
1114
|
+
const visibility = syncManagedOmpVisibility(effectiveChannels, config, options);
|
|
1115
|
+
const validation = options.validateWithCli === true
|
|
922
1116
|
? validateOmpModelsConfig(options)
|
|
923
1117
|
: { skipped: true, reason: 'cli-validation-disabled', warnings: [] };
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
path: paths.modelsYml,
|
|
927
|
-
modelsPath: paths.modelsYml,
|
|
928
|
-
settingsPath: visibility.settingsPath,
|
|
929
|
-
statePath: visibility.statePath,
|
|
930
|
-
backupPath,
|
|
931
|
-
modelsBackupPath: backupPath,
|
|
932
|
-
settingsBackupPath: visibility.settingsBackupPath,
|
|
933
|
-
changed: before !== after,
|
|
934
|
-
visibilityChanged: visibility.changed,
|
|
935
|
-
stateRemoved: visibility.stateRemoved,
|
|
936
|
-
validation,
|
|
937
|
-
warnings: [
|
|
1118
|
+
const warnings = [
|
|
1119
|
+
...buildWarnings,
|
|
938
1120
|
...(visibility.warnings || []),
|
|
939
1121
|
...(validation.warnings || [])
|
|
940
|
-
]
|
|
941
|
-
|
|
942
|
-
|
|
1122
|
+
];
|
|
1123
|
+
recordManagedOmpSyncResult({
|
|
1124
|
+
path: paths.modelsYml,
|
|
1125
|
+
modelsPath: paths.modelsYml,
|
|
1126
|
+
settingsPath: visibility.settingsPath,
|
|
1127
|
+
statePath: visibility.statePath,
|
|
1128
|
+
backupPath,
|
|
1129
|
+
modelsBackupPath: backupPath,
|
|
1130
|
+
settingsBackupPath: visibility.settingsBackupPath,
|
|
1131
|
+
changed: true,
|
|
1132
|
+
visibilityChanged: visibility.changed,
|
|
1133
|
+
managedEnabledModels: visibility.managedEnabledModels,
|
|
1134
|
+
managedEnabledModelsForSettings: visibility.managedEnabledModelsForSettings,
|
|
1135
|
+
managedDisabledProviders: visibility.managedDisabledProviders,
|
|
1136
|
+
managedDefaultModel: visibility.managedDefaultModel,
|
|
1137
|
+
validation,
|
|
1138
|
+
warnings
|
|
1139
|
+
});
|
|
1140
|
+
removeLegacyManagedExtension(paths);
|
|
1141
|
+
return paths.modelsYml;
|
|
1142
|
+
} catch (error) {
|
|
1143
|
+
restoreFileSnapshots(snapshots);
|
|
1144
|
+
throw error;
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
function removeManagedOmpProviders(options = {}) {
|
|
1149
|
+
const paths = getOmpPaths();
|
|
1150
|
+
const settingsPath = getOmpSettingsPath(paths);
|
|
1151
|
+
const statePath = getManagedVisibilityStatePath(paths);
|
|
1152
|
+
const snapshots = captureFileSnapshots([paths.modelsYml, settingsPath, statePath]);
|
|
1153
|
+
try {
|
|
1154
|
+
const config = readModelsConfig(paths.modelsYml);
|
|
1155
|
+
const visibility = removeManagedOmpVisibility(options);
|
|
1156
|
+
const before = Object.keys(config.providers || {}).length;
|
|
1157
|
+
pruneManagedProviders(config.providers);
|
|
1158
|
+
const after = Object.keys(config.providers || {}).length;
|
|
1159
|
+
let backupPath = null;
|
|
1160
|
+
let validation = {
|
|
1161
|
+
skipped: true,
|
|
1162
|
+
reason: before === after ? 'no-managed-providers' : 'not-run',
|
|
1163
|
+
warnings: []
|
|
1164
|
+
};
|
|
1165
|
+
if (before !== after) {
|
|
1166
|
+
backupPath = createModelsBackupIfNeeded(paths.modelsYml, options);
|
|
1167
|
+
writeModelsConfig(config, paths.modelsYml);
|
|
1168
|
+
validation = options.validateWithCli === true
|
|
1169
|
+
? validateOmpModelsConfig(options)
|
|
1170
|
+
: { skipped: true, reason: 'cli-validation-disabled', warnings: [] };
|
|
1171
|
+
}
|
|
1172
|
+
recordManagedOmpSyncResult({
|
|
1173
|
+
path: paths.modelsYml,
|
|
1174
|
+
modelsPath: paths.modelsYml,
|
|
1175
|
+
settingsPath: visibility.settingsPath,
|
|
1176
|
+
statePath: visibility.statePath,
|
|
1177
|
+
backupPath,
|
|
1178
|
+
modelsBackupPath: backupPath,
|
|
1179
|
+
settingsBackupPath: visibility.settingsBackupPath,
|
|
1180
|
+
changed: before !== after,
|
|
1181
|
+
visibilityChanged: visibility.changed,
|
|
1182
|
+
stateRemoved: visibility.stateRemoved,
|
|
1183
|
+
validation,
|
|
1184
|
+
warnings: [
|
|
1185
|
+
...(visibility.warnings || []),
|
|
1186
|
+
...(validation.warnings || [])
|
|
1187
|
+
]
|
|
1188
|
+
});
|
|
1189
|
+
removeLegacyManagedExtension(paths);
|
|
1190
|
+
} catch (error) {
|
|
1191
|
+
restoreFileSnapshots(snapshots);
|
|
1192
|
+
throw error;
|
|
1193
|
+
}
|
|
943
1194
|
}
|
|
944
1195
|
|
|
945
1196
|
function isManagedOmpProvidersActive() {
|