coding-tool-x 3.6.13 → 3.7.1
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/README.md +45 -33
- package/dist/web/assets/{Analytics-CnA75GxO.js → Analytics-Dpje9L84.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-D8XEscQY.js → ConfigTemplates-Cz6kasek.js} +1 -1
- package/dist/web/assets/Home-BwTaYu3q.js +1 -0
- package/dist/web/assets/Home-Jom_ZcdY.css +1 -0
- package/dist/web/assets/{PluginManager-BzKZ8TYu.js → PluginManager-DsN-xNXx.js} +1 -1
- package/dist/web/assets/ProjectList-4BCObimU.js +1 -0
- package/dist/web/assets/{ProjectList-DL4JK6ci.css → ProjectList-D3a0oRum.css} +1 -1
- package/dist/web/assets/SessionList-D4c8FRzq.js +1 -0
- package/dist/web/assets/{SkillManager-fxOvFTYD.js → SkillManager-C-KYbXB5.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-Ch2mM8jm.js → WorkspaceManager-B-BlPJHX.js} +1 -1
- package/dist/web/assets/{icons-QFXzEgqM.js → icons-Dop5j7Bf.js} +1 -1
- package/dist/web/assets/index-Btfvh0GG.js +2 -0
- package/dist/web/assets/index-CLNa6DhH.css +1 -0
- package/dist/web/assets/{naive-ui-kcWDeJwl.js → naive-ui-CVyvdmg1.js} +1 -1
- package/dist/web/index.html +4 -4
- package/package.json +3 -1
- package/src/commands/channels.js +85 -24
- package/src/commands/daemon.js +7 -4
- package/src/commands/doctor.js +17 -8
- package/src/commands/logs.js +46 -6
- package/src/commands/port-config.js +83 -75
- package/src/commands/proxy-control.js +59 -26
- package/src/commands/stats.js +37 -19
- package/src/commands/switch.js +5 -1
- package/src/commands/toggle-proxy.js +131 -53
- package/src/commands/ui.js +3 -4
- package/src/commands/workspace.js +3 -35
- package/src/config/default.js +19 -2
- package/src/config/loader.js +5 -76
- package/src/config/paths.js +96 -11
- package/src/index.js +10 -16
- package/src/server/api/commands.js +1 -1
- package/src/server/api/config-export.js +4 -2
- package/src/server/api/config-registry.js +40 -34
- package/src/server/api/config.js +5 -1
- package/src/server/api/dashboard.js +22 -6
- package/src/server/api/mcp.js +5 -3
- package/src/server/api/omp-channels.js +349 -0
- package/src/server/api/omp-config.js +164 -0
- package/src/server/api/omp-projects.js +76 -0
- package/src/server/api/omp-proxy.js +154 -0
- package/src/server/api/omp-sessions.js +334 -0
- package/src/server/api/omp-statistics.js +40 -0
- package/src/server/api/plugins.js +1 -1
- package/src/server/api/prompts.js +3 -2
- package/src/server/api/settings.js +2 -0
- package/src/server/api/skills.js +1 -1
- package/src/server/api/workspaces.js +3 -41
- package/src/server/index.js +41 -0
- package/src/server/omp-proxy-server.js +66 -0
- package/src/server/services/agents-service.js +2 -1
- package/src/server/services/base/proxy-utils.js +1 -0
- package/src/server/services/channel-balance.js +151 -1
- package/src/server/services/channel-scheduler.js +7 -1
- package/src/server/services/commands-service.js +11 -2
- package/src/server/services/config-export-service.js +296 -39
- package/src/server/services/config-registry-service.js +20 -18
- package/src/server/services/config-sync-manager.js +115 -6
- package/src/server/services/config-sync-service.js +4 -2
- package/src/server/services/config-templates-service.js +183 -45
- package/src/server/services/mcp-service.js +217 -33
- package/src/server/services/notification-hooks.js +138 -6
- package/src/server/services/omp-auth-providers.js +294 -0
- package/src/server/services/omp-channels.js +94 -0
- package/src/server/services/omp-config.js +269 -0
- package/src/server/services/omp-sessions.js +490 -0
- package/src/server/services/omp-settings-manager.js +975 -0
- package/src/server/services/omp-statistics-service.js +317 -0
- package/src/server/services/plugins-service.js +673 -11
- package/src/server/services/prompts-service.js +112 -7
- package/src/server/services/proxy-log-helper.js +1 -0
- package/src/server/services/proxy-runtime.js +5 -1
- package/src/server/services/sessions.js +19 -35
- package/src/server/services/skill-service.js +13 -3
- package/src/server/services/speed-test.js +34 -28
- package/src/server/services/ui-config.js +50 -12
- package/src/server/services/workspace-service.js +117 -225
- package/src/server/websocket-server.js +7 -1
- package/src/shared/platforms.js +201 -0
- package/src/utils/session.js +4 -10
- package/dist/web/assets/Home-BiaKZMah.js +0 -1
- package/dist/web/assets/Home-CIua-b-o.css +0 -1
- package/dist/web/assets/ProjectList-BPfG_92X.js +0 -1
- package/dist/web/assets/SessionList-BIVtw00v.js +0 -1
- package/dist/web/assets/index-BpBFF3b2.js +0 -2
- package/dist/web/assets/index-Dsh4Q5Cg.css +0 -1
- package/src/utils/cli-flags.js +0 -7
|
@@ -12,12 +12,14 @@ const path = require('path');
|
|
|
12
12
|
const { execFileSync } = require('child_process');
|
|
13
13
|
const toml = require('toml');
|
|
14
14
|
const tomlStringify = require('@iarna/toml').stringify;
|
|
15
|
+
const yaml = require('js-yaml');
|
|
15
16
|
const AdmZip = require('adm-zip');
|
|
16
17
|
const { listPlugins, getPlugin, updatePlugin: updatePluginRegistry } = require('../../plugins/registry');
|
|
17
18
|
const { installPlugin: installPluginCore, uninstallPlugin: uninstallPluginCore } = require('../../plugins/plugin-installer');
|
|
18
19
|
const { initializePlugins, shutdownPlugins } = require('../../plugins/plugin-manager');
|
|
19
20
|
const { INSTALLED_DIR, CONFIG_DIR } = require('../../plugins/constants');
|
|
20
21
|
const { NATIVE_PATHS, PATHS } = require('../../config/paths');
|
|
22
|
+
const { getOmpCommand } = require('./omp-config');
|
|
21
23
|
const { maskToken } = require('./oauth-utils');
|
|
22
24
|
const {
|
|
23
25
|
assertInsideAllowedRoots,
|
|
@@ -26,7 +28,8 @@ const {
|
|
|
26
28
|
resolveInsideRoot
|
|
27
29
|
} = require('./config-artifact-paths');
|
|
28
30
|
|
|
29
|
-
const CLAUDE_PLUGINS_DIR =
|
|
31
|
+
const CLAUDE_PLUGINS_DIR = NATIVE_PATHS.claude.plugins
|
|
32
|
+
|| path.join(NATIVE_PATHS.claude.dir || path.dirname(NATIVE_PATHS.claude.settings), 'plugins');
|
|
30
33
|
const CLAUDE_INSTALLED_FILE = path.join(CLAUDE_PLUGINS_DIR, 'installed_plugins.json');
|
|
31
34
|
const CLAUDE_MARKETPLACES_FILE = path.join(CLAUDE_PLUGINS_DIR, 'known_marketplaces.json');
|
|
32
35
|
const CLAUDE_PLUGINS_CACHE_DIR = path.join(CLAUDE_PLUGINS_DIR, 'cache');
|
|
@@ -42,9 +45,10 @@ const DEFAULT_REPOS_BY_PLATFORM = {
|
|
|
42
45
|
claude: [],
|
|
43
46
|
codex: [],
|
|
44
47
|
gemini: [],
|
|
45
|
-
opencode: []
|
|
48
|
+
opencode: [],
|
|
49
|
+
omp: []
|
|
46
50
|
};
|
|
47
|
-
const SUPPORTED_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode'];
|
|
51
|
+
const SUPPORTED_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode', 'omp'];
|
|
48
52
|
const PLATFORM_CAPABILITIES = {
|
|
49
53
|
claude: {
|
|
50
54
|
platform: 'claude',
|
|
@@ -94,6 +98,19 @@ const PLATFORM_CAPABILITIES = {
|
|
|
94
98
|
config: true,
|
|
95
99
|
import: false,
|
|
96
100
|
syncRepos: false
|
|
101
|
+
},
|
|
102
|
+
omp: {
|
|
103
|
+
platform: 'omp',
|
|
104
|
+
supportsPlugins: true,
|
|
105
|
+
repositories: true,
|
|
106
|
+
market: true,
|
|
107
|
+
install: true,
|
|
108
|
+
uninstall: true,
|
|
109
|
+
toggle: true,
|
|
110
|
+
config: true,
|
|
111
|
+
import: false,
|
|
112
|
+
syncRepos: false,
|
|
113
|
+
pluginKindLabel: 'packages/extensions'
|
|
97
114
|
}
|
|
98
115
|
};
|
|
99
116
|
|
|
@@ -177,6 +194,134 @@ function splitPluginMarketplaceKey(key = '') {
|
|
|
177
194
|
};
|
|
178
195
|
}
|
|
179
196
|
|
|
197
|
+
function normalizeOmpPackageEntry(item = null) {
|
|
198
|
+
if (typeof item === 'string') {
|
|
199
|
+
const name = item.trim();
|
|
200
|
+
return name ? {
|
|
201
|
+
name,
|
|
202
|
+
source: name,
|
|
203
|
+
directory: name,
|
|
204
|
+
installSource: name,
|
|
205
|
+
resourceTypes: []
|
|
206
|
+
} : null;
|
|
207
|
+
}
|
|
208
|
+
if (!item || typeof item !== 'object') return null;
|
|
209
|
+
|
|
210
|
+
const rawName = item.name || item.package || item.id || item.source || item.path || '';
|
|
211
|
+
const name = String(rawName || '').trim();
|
|
212
|
+
if (!name) return null;
|
|
213
|
+
|
|
214
|
+
const directory = String(item.directory || item.path || name).trim() || name;
|
|
215
|
+
const installSource = String(item.installSource || item.source || item.url || item.packageSource || name).trim() || name;
|
|
216
|
+
return {
|
|
217
|
+
...item,
|
|
218
|
+
name,
|
|
219
|
+
source: item.source || installSource,
|
|
220
|
+
directory,
|
|
221
|
+
installSource,
|
|
222
|
+
resourceTypes: normalizeOmpResourceTypes(item.resourceTypes || item.resources || item.provides || item.capabilities)
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function getOmpPackageIdentity(item = null) {
|
|
227
|
+
const normalized = normalizeOmpPackageEntry(item);
|
|
228
|
+
return normalized?.name || '';
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function ompPackageSettingValue(item = null) {
|
|
232
|
+
const normalized = normalizeOmpPackageEntry(item);
|
|
233
|
+
if (!normalized) return null;
|
|
234
|
+
if (typeof item === 'string') return normalized.name;
|
|
235
|
+
|
|
236
|
+
const next = { ...item };
|
|
237
|
+
next.name = normalized.name;
|
|
238
|
+
next.directory = normalized.directory;
|
|
239
|
+
next.source = normalized.installSource;
|
|
240
|
+
const resourceTypes = normalizeOmpResourceTypes(next.resourceTypes || next.resources || normalized.resourceTypes);
|
|
241
|
+
if (resourceTypes.length > 0) {
|
|
242
|
+
next.resourceTypes = resourceTypes;
|
|
243
|
+
} else {
|
|
244
|
+
delete next.resourceTypes;
|
|
245
|
+
}
|
|
246
|
+
return next;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function normalizeOmpResourceType(value = '') {
|
|
250
|
+
const normalized = String(value || '').trim();
|
|
251
|
+
if (!normalized) return '';
|
|
252
|
+
const key = normalized
|
|
253
|
+
.replace(/[\s_-]+/g, '')
|
|
254
|
+
.toLowerCase();
|
|
255
|
+
const map = {
|
|
256
|
+
extension: 'extension',
|
|
257
|
+
extensions: 'extension',
|
|
258
|
+
plugin: 'extension',
|
|
259
|
+
plugins: 'extension',
|
|
260
|
+
skill: 'skill',
|
|
261
|
+
skills: 'skill',
|
|
262
|
+
prompt: 'promptTemplate',
|
|
263
|
+
prompts: 'promptTemplate',
|
|
264
|
+
prompttemplate: 'promptTemplate',
|
|
265
|
+
prompttemplates: 'promptTemplate',
|
|
266
|
+
prompttemplating: 'promptTemplate',
|
|
267
|
+
command: 'promptTemplate',
|
|
268
|
+
commands: 'promptTemplate',
|
|
269
|
+
theme: 'theme',
|
|
270
|
+
themes: 'theme',
|
|
271
|
+
mcp: 'mcp',
|
|
272
|
+
subagent: 'subagent',
|
|
273
|
+
subagents: 'subagent',
|
|
274
|
+
agent: 'subagent',
|
|
275
|
+
agents: 'subagent'
|
|
276
|
+
};
|
|
277
|
+
return map[key] || normalized;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function normalizeOmpResourceTypes(input = []) {
|
|
281
|
+
const values = [];
|
|
282
|
+
const pushValue = (value) => {
|
|
283
|
+
const normalized = normalizeOmpResourceType(value);
|
|
284
|
+
if (normalized && !values.includes(normalized)) values.push(normalized);
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
if (Array.isArray(input)) {
|
|
288
|
+
input.forEach(pushValue);
|
|
289
|
+
} else if (input && typeof input === 'object') {
|
|
290
|
+
for (const [key, value] of Object.entries(input)) {
|
|
291
|
+
if (value === false || value == null) continue;
|
|
292
|
+
if (Array.isArray(value)) {
|
|
293
|
+
if (value.length > 0) pushValue(key);
|
|
294
|
+
} else if (typeof value === 'object') {
|
|
295
|
+
if (Object.keys(value).length > 0) pushValue(key);
|
|
296
|
+
} else {
|
|
297
|
+
pushValue(key);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
} else if (input) {
|
|
301
|
+
pushValue(input);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return values;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function isOmpPackageInstallSource(value = '') {
|
|
308
|
+
const source = String(value || '').trim();
|
|
309
|
+
if (!source) return false;
|
|
310
|
+
if (isLikelyLocalPath(source)) return true;
|
|
311
|
+
if (/^(npm|git):/i.test(source)) return true;
|
|
312
|
+
if (/^https?:\/\//i.test(source)) return true;
|
|
313
|
+
if (/^ssh:\/\//i.test(source)) return true;
|
|
314
|
+
if (/^git@[^:]+:.+/i.test(source)) return true;
|
|
315
|
+
return !source.startsWith('-');
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function normalizeMarketplaceSkillPaths(skills = []) {
|
|
319
|
+
if (!Array.isArray(skills)) return [];
|
|
320
|
+
return skills
|
|
321
|
+
.map(skill => normalizeRepoPath(String(skill || '').replace(/^\.\//, '')))
|
|
322
|
+
.filter(Boolean);
|
|
323
|
+
}
|
|
324
|
+
|
|
180
325
|
function hasRepoInstallInfo(repoInfo = null) {
|
|
181
326
|
return Boolean(
|
|
182
327
|
repoInfo &&
|
|
@@ -544,11 +689,14 @@ class PluginsService {
|
|
|
544
689
|
plugin.repoId || '',
|
|
545
690
|
plugin.repoProvider || '',
|
|
546
691
|
plugin.repoOwner || '',
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
692
|
+
plugin.repoName || '',
|
|
693
|
+
plugin.repoProjectPath || '',
|
|
694
|
+
plugin.repoLocalPath || '',
|
|
695
|
+
plugin.directory || '',
|
|
696
|
+
plugin.installSource || '',
|
|
697
|
+
plugin.pluginKind || '',
|
|
698
|
+
plugin.marketplaceFormat || ''
|
|
699
|
+
].join('::');
|
|
552
700
|
if (seen.has(key)) continue;
|
|
553
701
|
seen.add(key);
|
|
554
702
|
deduped.push({
|
|
@@ -571,6 +719,10 @@ class PluginsService {
|
|
|
571
719
|
return this.platform === 'opencode';
|
|
572
720
|
}
|
|
573
721
|
|
|
722
|
+
_isOmp() {
|
|
723
|
+
return this.platform === 'omp';
|
|
724
|
+
}
|
|
725
|
+
|
|
574
726
|
_isCodex() {
|
|
575
727
|
return this.platform === 'codex';
|
|
576
728
|
}
|
|
@@ -596,6 +748,194 @@ class PluginsService {
|
|
|
596
748
|
return json;
|
|
597
749
|
}
|
|
598
750
|
|
|
751
|
+
_readOmpSettings() {
|
|
752
|
+
const filePath = NATIVE_PATHS.omp.settings;
|
|
753
|
+
if (!fs.existsSync(filePath)) {
|
|
754
|
+
const legacyPath = NATIVE_PATHS.omp.settingsJsonLegacy;
|
|
755
|
+
if (legacyPath && fs.existsSync(legacyPath)) {
|
|
756
|
+
try {
|
|
757
|
+
const raw = fs.readFileSync(legacyPath, 'utf8');
|
|
758
|
+
return raw.trim() ? JSON.parse(raw) : {};
|
|
759
|
+
} catch (err) {
|
|
760
|
+
console.error('[PluginsService] Failed to read legacy OMP settings:', err.message);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
return {};
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
try {
|
|
767
|
+
const raw = fs.readFileSync(filePath, 'utf8');
|
|
768
|
+
const parsed = raw.trim() ? yaml.load(raw) : {};
|
|
769
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
|
|
770
|
+
} catch (err) {
|
|
771
|
+
console.error('[PluginsService] Failed to read OMP settings:', err.message);
|
|
772
|
+
return {};
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
_writeOmpSettings(settings = {}) {
|
|
777
|
+
this._ensureDir(path.dirname(NATIVE_PATHS.omp.settings));
|
|
778
|
+
fs.writeFileSync(NATIVE_PATHS.omp.settings, yaml.dump(settings, {
|
|
779
|
+
lineWidth: 120,
|
|
780
|
+
noRefs: true,
|
|
781
|
+
sortKeys: false
|
|
782
|
+
}), 'utf8');
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
_listOmpPackages() {
|
|
786
|
+
const settings = this._readOmpSettings();
|
|
787
|
+
return Array.isArray(settings.packages)
|
|
788
|
+
? settings.packages.map(normalizeOmpPackageEntry).filter(Boolean)
|
|
789
|
+
: [];
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
_setOmpPackages(packages = []) {
|
|
793
|
+
const settings = this._readOmpSettings();
|
|
794
|
+
const seen = new Set();
|
|
795
|
+
settings.packages = packages
|
|
796
|
+
.map(item => ompPackageSettingValue(item))
|
|
797
|
+
.filter((item) => {
|
|
798
|
+
const name = getOmpPackageIdentity(item);
|
|
799
|
+
if (!name || seen.has(name)) return false;
|
|
800
|
+
seen.add(name);
|
|
801
|
+
return true;
|
|
802
|
+
});
|
|
803
|
+
this._writeOmpSettings(settings);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
_listOmpDisabledPackageEntries() {
|
|
807
|
+
const settings = this._readOmpSettings();
|
|
808
|
+
return Array.isArray(settings.disabledPackages)
|
|
809
|
+
? settings.disabledPackages.map(normalizeOmpPackageEntry).filter(Boolean)
|
|
810
|
+
: [];
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
_listOmpDisabledPackages() {
|
|
814
|
+
return this._listOmpDisabledPackageEntries().map(item => item.name).filter(Boolean);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
_setOmpDisabledPackages(packages = []) {
|
|
818
|
+
const settings = this._readOmpSettings();
|
|
819
|
+
const seen = new Set();
|
|
820
|
+
settings.disabledPackages = packages
|
|
821
|
+
.map(item => ompPackageSettingValue(item))
|
|
822
|
+
.filter((item) => {
|
|
823
|
+
const name = getOmpPackageIdentity(item);
|
|
824
|
+
if (!name || seen.has(name)) return false;
|
|
825
|
+
seen.add(name);
|
|
826
|
+
return true;
|
|
827
|
+
});
|
|
828
|
+
this._writeOmpSettings(settings);
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
_runOmpPackageCommand(args = []) {
|
|
832
|
+
execFileSync(getOmpCommand(), args, {
|
|
833
|
+
cwd: process.cwd(),
|
|
834
|
+
encoding: 'utf8',
|
|
835
|
+
stdio: 'pipe',
|
|
836
|
+
timeout: 120000
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
_registerOmpPackageReference(packageName, metadata = {}) {
|
|
841
|
+
const packages = this._listOmpPackages();
|
|
842
|
+
const installSource = String(metadata.installSource || metadata.source || packageName || '').trim();
|
|
843
|
+
const displayName = String(metadata.name || packageName || installSource).trim();
|
|
844
|
+
if (!packages.some(pkg => pkg.name === displayName || pkg.installSource === installSource)) {
|
|
845
|
+
const resourceTypes = normalizeOmpResourceTypes(metadata.resourceTypes || metadata.resources);
|
|
846
|
+
const entry = installSource && installSource !== displayName
|
|
847
|
+
? {
|
|
848
|
+
name: displayName,
|
|
849
|
+
source: installSource,
|
|
850
|
+
...(metadata.version ? { version: metadata.version } : {}),
|
|
851
|
+
...(metadata.description ? { description: metadata.description } : {}),
|
|
852
|
+
...(resourceTypes.length > 0 ? { resourceTypes } : {})
|
|
853
|
+
}
|
|
854
|
+
: displayName;
|
|
855
|
+
packages.push(entry);
|
|
856
|
+
this._setOmpPackages(packages);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
_buildOmpPackagePlugin(packageName, metadata = {}) {
|
|
861
|
+
const installSource = String(metadata.installSource || metadata.source || packageName || '').trim();
|
|
862
|
+
const name = String(metadata.name || packageName || installSource).trim();
|
|
863
|
+
const resourceTypes = normalizeOmpResourceTypes(metadata.resourceTypes || metadata.resources);
|
|
864
|
+
return {
|
|
865
|
+
name,
|
|
866
|
+
directory: name,
|
|
867
|
+
installSource: installSource || name,
|
|
868
|
+
version: metadata.version || 'latest',
|
|
869
|
+
description: metadata.description || '',
|
|
870
|
+
pluginKind: 'package',
|
|
871
|
+
pluginType: 'package',
|
|
872
|
+
...(resourceTypes.length > 0 ? { resourceTypes } : {})
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
_installOmpPackage(packageName, metadata = {}) {
|
|
877
|
+
const installSource = String(metadata.installSource || metadata.source || packageName || '').trim();
|
|
878
|
+
const plugin = this._buildOmpPackagePlugin(packageName, { ...metadata, installSource });
|
|
879
|
+
try {
|
|
880
|
+
this._runOmpPackageCommand(['install', installSource || packageName]);
|
|
881
|
+
return {
|
|
882
|
+
success: true,
|
|
883
|
+
plugin
|
|
884
|
+
};
|
|
885
|
+
} catch (err) {
|
|
886
|
+
this._registerOmpPackageReference(packageName, { ...metadata, installSource, name: plugin.name });
|
|
887
|
+
return {
|
|
888
|
+
success: true,
|
|
889
|
+
registeredOnly: true,
|
|
890
|
+
warning: `Failed to run "${getOmpCommand()} install"; saved the package reference so OMP can resolve it later. ${err.message}`,
|
|
891
|
+
plugin
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
_removeOmpPackage(packageName) {
|
|
897
|
+
try {
|
|
898
|
+
this._runOmpPackageCommand(['remove', packageName]);
|
|
899
|
+
return true;
|
|
900
|
+
} catch (err) {
|
|
901
|
+
return false;
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
_listOmpLocalExtensions() {
|
|
906
|
+
const plugins = [];
|
|
907
|
+
const extensionsDir = NATIVE_PATHS.omp.extensions;
|
|
908
|
+
if (!fs.existsSync(extensionsDir)) return plugins;
|
|
909
|
+
|
|
910
|
+
try {
|
|
911
|
+
const disabled = new Set(this._listOmpDisabledPackages());
|
|
912
|
+
const entries = fs.readdirSync(extensionsDir, { withFileTypes: true });
|
|
913
|
+
for (const entry of entries) {
|
|
914
|
+
if (entry.name.startsWith('.')) continue;
|
|
915
|
+
const fullPath = path.join(extensionsDir, entry.name);
|
|
916
|
+
const ext = path.extname(entry.name).toLowerCase();
|
|
917
|
+
if (!entry.isDirectory() && !['.js', '.mjs', '.cjs', '.ts'].includes(ext)) continue;
|
|
918
|
+
const name = entry.isDirectory() ? entry.name : entry.name.slice(0, -ext.length);
|
|
919
|
+
plugins.push({
|
|
920
|
+
name,
|
|
921
|
+
directory: entry.name,
|
|
922
|
+
installPath: fullPath,
|
|
923
|
+
source: 'omp-extension',
|
|
924
|
+
version: 'local',
|
|
925
|
+
description: '',
|
|
926
|
+
installed: true,
|
|
927
|
+
enabled: !disabled.has(name) && !disabled.has(entry.name),
|
|
928
|
+
pluginType: entry.isDirectory() ? 'extension-directory' : 'extension-file',
|
|
929
|
+
pluginKind: 'extension'
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
} catch (err) {
|
|
933
|
+
console.error('[PluginsService] Failed to list OMP extensions:', err.message);
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
return plugins;
|
|
937
|
+
}
|
|
938
|
+
|
|
599
939
|
_readOpenCodeConfig() {
|
|
600
940
|
const filePath = this._getOpenCodeConfigPath();
|
|
601
941
|
if (!fs.existsSync(filePath)) return { filePath, config: {} };
|
|
@@ -1112,6 +1452,41 @@ class PluginsService {
|
|
|
1112
1452
|
return { plugins };
|
|
1113
1453
|
}
|
|
1114
1454
|
|
|
1455
|
+
if (this._isOmp()) {
|
|
1456
|
+
const disabledEntries = this._listOmpDisabledPackageEntries();
|
|
1457
|
+
const disabled = new Set(disabledEntries.flatMap(item => [item.name, item.installSource].filter(Boolean)));
|
|
1458
|
+
const plugins = [];
|
|
1459
|
+
const seen = new Set();
|
|
1460
|
+
|
|
1461
|
+
for (const pkg of this._listOmpPackages()) {
|
|
1462
|
+
const seenKey = pkg.installSource || pkg.name;
|
|
1463
|
+
if (seen.has(seenKey)) continue;
|
|
1464
|
+
seen.add(seenKey);
|
|
1465
|
+
plugins.push({
|
|
1466
|
+
...pkg,
|
|
1467
|
+
name: pkg.name,
|
|
1468
|
+
directory: pkg.directory || pkg.name,
|
|
1469
|
+
installSource: pkg.installSource || pkg.source || pkg.name,
|
|
1470
|
+
resourceTypes: normalizeOmpResourceTypes(pkg.resourceTypes || pkg.resources),
|
|
1471
|
+
source: 'omp-settings',
|
|
1472
|
+
version: pkg.version || 'latest',
|
|
1473
|
+
description: pkg.description || '',
|
|
1474
|
+
installed: true,
|
|
1475
|
+
enabled: !disabled.has(pkg.name) && !disabled.has(pkg.installSource),
|
|
1476
|
+
pluginType: 'package',
|
|
1477
|
+
pluginKind: 'package'
|
|
1478
|
+
});
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
for (const extension of this._listOmpLocalExtensions()) {
|
|
1482
|
+
if (seen.has(extension.name)) continue;
|
|
1483
|
+
seen.add(extension.name);
|
|
1484
|
+
plugins.push(extension);
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
return { plugins };
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1115
1490
|
const plugins = [];
|
|
1116
1491
|
|
|
1117
1492
|
// Read Claude Code's installed_plugins.json
|
|
@@ -1251,6 +1626,12 @@ class PluginsService {
|
|
|
1251
1626
|
return plugin;
|
|
1252
1627
|
}
|
|
1253
1628
|
|
|
1629
|
+
if (this._isOmp()) {
|
|
1630
|
+
const plugin = this.listPlugins().plugins.find(p => p.name === name || p.directory === name);
|
|
1631
|
+
if (!plugin) return null;
|
|
1632
|
+
return plugin;
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1254
1635
|
const plugin = getPlugin(name);
|
|
1255
1636
|
if (!plugin) {
|
|
1256
1637
|
return null;
|
|
@@ -1314,6 +1695,51 @@ class PluginsService {
|
|
|
1314
1695
|
};
|
|
1315
1696
|
}
|
|
1316
1697
|
|
|
1698
|
+
if (this._isOmp()) {
|
|
1699
|
+
const packageMetadata = repoInfo && typeof repoInfo === 'object'
|
|
1700
|
+
? {
|
|
1701
|
+
name: repoInfo.name || repoInfo.packageName || repoInfo.displayName,
|
|
1702
|
+
version: repoInfo.version,
|
|
1703
|
+
description: repoInfo.description,
|
|
1704
|
+
resourceTypes: repoInfo.resourceTypes || repoInfo.resources,
|
|
1705
|
+
installSource: repoInfo.installSource || repoInfo.source
|
|
1706
|
+
}
|
|
1707
|
+
: {};
|
|
1708
|
+
const explicitPackageSource = String(source || packageMetadata.installSource || '').trim();
|
|
1709
|
+
|
|
1710
|
+
if (
|
|
1711
|
+
repoInfo?.pluginKind === 'package' ||
|
|
1712
|
+
repoInfo?.pluginType === 'package' ||
|
|
1713
|
+
(explicitPackageSource && isOmpPackageInstallSource(explicitPackageSource) && !hasRepoInstallInfo(repoInfo))
|
|
1714
|
+
) {
|
|
1715
|
+
return this._installOmpPackage(explicitPackageSource, packageMetadata);
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
if (hasRepoInstallInfo(repoInfo)) {
|
|
1719
|
+
return this._installFromRepoDirectory(repoInfo, { installRoot: NATIVE_PATHS.omp.extensions });
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
const parsedSource = this.parseRepoTreeSource(source);
|
|
1723
|
+
if (parsedSource) {
|
|
1724
|
+
return this._installOmpPackage(source);
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
const parsedRepo = this._repoFromGitUrl(source, 'main');
|
|
1728
|
+
if (parsedRepo) {
|
|
1729
|
+
return this._installOmpPackage(source);
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
const packageName = String(source || '').trim();
|
|
1733
|
+
if (packageName && isOmpPackageInstallSource(packageName)) {
|
|
1734
|
+
return this._installOmpPackage(packageName);
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
return {
|
|
1738
|
+
success: false,
|
|
1739
|
+
error: 'OMP plugin install expects package name, repository metadata, a GitHub/GitLab tree URL, or a Git repository URL'
|
|
1740
|
+
};
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1317
1743
|
if (this._isOpenCode()) {
|
|
1318
1744
|
if (hasRepoInstallInfo(repoInfo)) {
|
|
1319
1745
|
return this._installFromRepoDirectory(repoInfo, { installRoot: this._getOpenCodePluginsDir() });
|
|
@@ -1552,7 +1978,7 @@ class PluginsService {
|
|
|
1552
1978
|
} catch (e) {
|
|
1553
1979
|
console.error('[PluginsService] Failed to update native installed_plugins.json:', e.message);
|
|
1554
1980
|
}
|
|
1555
|
-
} else if (!this._isOpenCode()) {
|
|
1981
|
+
} else if (!this._isOpenCode() && !this._isOmp()) {
|
|
1556
1982
|
const installTimestamp = new Date().toISOString();
|
|
1557
1983
|
const sourceUrl = this.buildRepoBrowserUrl(normalizedRepo, directory) || buildRepoUrl(normalizedRepo);
|
|
1558
1984
|
const repoSourceMeta = {
|
|
@@ -1582,6 +2008,21 @@ class PluginsService {
|
|
|
1582
2008
|
}
|
|
1583
2009
|
|
|
1584
2010
|
this.writeRepoSourceMeta(pluginDir, repoSourceMeta);
|
|
2011
|
+
} else if (this._isOmp()) {
|
|
2012
|
+
const sourceUrl = this.buildRepoBrowserUrl(normalizedRepo, directory) || buildRepoUrl(normalizedRepo);
|
|
2013
|
+
this.writeRepoSourceMeta(pluginDir, {
|
|
2014
|
+
repoId: normalizedRepo.id,
|
|
2015
|
+
repoProvider: normalizedRepo.provider,
|
|
2016
|
+
repoOwner: normalizedRepo.owner || '',
|
|
2017
|
+
repoName: normalizedRepo.name || '',
|
|
2018
|
+
repoBranch: normalizedRepo.branch,
|
|
2019
|
+
repoDirectory: directory,
|
|
2020
|
+
repoHost: normalizedRepo.host || '',
|
|
2021
|
+
repoProjectPath: normalizedRepo.projectPath || '',
|
|
2022
|
+
repoLocalPath: normalizedRepo.localPath || '',
|
|
2023
|
+
repoUrl: normalizedRepo.repoUrl || buildRepoUrl(normalizedRepo),
|
|
2024
|
+
source: sourceUrl
|
|
2025
|
+
});
|
|
1585
2026
|
}
|
|
1586
2027
|
|
|
1587
2028
|
return {
|
|
@@ -1607,6 +2048,9 @@ class PluginsService {
|
|
|
1607
2048
|
if (this._isOpenCode()) {
|
|
1608
2049
|
return ['package.json', 'plugin.json'];
|
|
1609
2050
|
}
|
|
2051
|
+
if (this._isOmp()) {
|
|
2052
|
+
return ['omp.json', 'extension.json', 'plugin.json', 'package.json'];
|
|
2053
|
+
}
|
|
1610
2054
|
return ['.claude-plugin/plugin.json', 'plugin.json', 'package.json'];
|
|
1611
2055
|
}
|
|
1612
2056
|
|
|
@@ -1738,6 +2182,71 @@ class PluginsService {
|
|
|
1738
2182
|
};
|
|
1739
2183
|
}
|
|
1740
2184
|
|
|
2185
|
+
if (this._isOmp()) {
|
|
2186
|
+
const targetName = String(name || '').trim();
|
|
2187
|
+
let safeName = '';
|
|
2188
|
+
try {
|
|
2189
|
+
safeName = normalizePluginPathName(targetName, 'plugin name');
|
|
2190
|
+
} catch {
|
|
2191
|
+
safeName = '';
|
|
2192
|
+
}
|
|
2193
|
+
const packages = this._listOmpPackages();
|
|
2194
|
+
let removed = false;
|
|
2195
|
+
const packageToRemove = packages.find(pkg =>
|
|
2196
|
+
pkg.name === targetName ||
|
|
2197
|
+
pkg.name === safeName ||
|
|
2198
|
+
pkg.installSource === targetName ||
|
|
2199
|
+
pkg.installSource === safeName
|
|
2200
|
+
);
|
|
2201
|
+
if (packageToRemove) {
|
|
2202
|
+
this._removeOmpPackage(packageToRemove.installSource || packageToRemove.name);
|
|
2203
|
+
}
|
|
2204
|
+
const nextPackages = packages.filter(pkg =>
|
|
2205
|
+
pkg.name !== safeName &&
|
|
2206
|
+
pkg.name !== targetName &&
|
|
2207
|
+
pkg.installSource !== safeName &&
|
|
2208
|
+
pkg.installSource !== targetName
|
|
2209
|
+
);
|
|
2210
|
+
if (nextPackages.length !== packages.length) {
|
|
2211
|
+
this._setOmpPackages(nextPackages);
|
|
2212
|
+
const disabledEntries = this._listOmpDisabledPackageEntries().filter(pkg =>
|
|
2213
|
+
pkg.name !== safeName &&
|
|
2214
|
+
pkg.name !== targetName &&
|
|
2215
|
+
pkg.installSource !== safeName &&
|
|
2216
|
+
pkg.installSource !== targetName &&
|
|
2217
|
+
pkg.name !== packageToRemove?.name &&
|
|
2218
|
+
pkg.installSource !== packageToRemove?.installSource
|
|
2219
|
+
);
|
|
2220
|
+
this._setOmpDisabledPackages(disabledEntries);
|
|
2221
|
+
removed = true;
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2224
|
+
const extensionsDir = NATIVE_PATHS.omp.extensions;
|
|
2225
|
+
if (safeName && fs.existsSync(extensionsDir)) {
|
|
2226
|
+
const directPath = resolveInsideRoot(extensionsDir, safeName, 'OMP extension path');
|
|
2227
|
+
if (fs.existsSync(directPath)) {
|
|
2228
|
+
fs.rmSync(directPath, { recursive: true, force: true });
|
|
2229
|
+
removed = true;
|
|
2230
|
+
} else {
|
|
2231
|
+
const entries = fs.readdirSync(extensionsDir, { withFileTypes: true });
|
|
2232
|
+
for (const entry of entries) {
|
|
2233
|
+
const baseName = entry.name.replace(path.extname(entry.name), '');
|
|
2234
|
+
if (entry.name === safeName || baseName === safeName) {
|
|
2235
|
+
const entryPath = resolveInsideRoot(extensionsDir, entry.name, 'OMP extension path');
|
|
2236
|
+
fs.rmSync(entryPath, { recursive: true, force: true });
|
|
2237
|
+
removed = true;
|
|
2238
|
+
break;
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
return {
|
|
2245
|
+
success: true,
|
|
2246
|
+
message: removed ? 'Plugin removed successfully' : 'Plugin not found'
|
|
2247
|
+
};
|
|
2248
|
+
}
|
|
2249
|
+
|
|
1741
2250
|
if (this._isOpenCode()) {
|
|
1742
2251
|
const safeName = normalizePluginPathName(name, 'plugin name');
|
|
1743
2252
|
const pluginsDir = this._getOpenCodePluginsDir();
|
|
@@ -1870,6 +2379,29 @@ class PluginsService {
|
|
|
1870
2379
|
throw new Error(`${this.platform} plugin management is not supported`);
|
|
1871
2380
|
}
|
|
1872
2381
|
|
|
2382
|
+
if (this._isOmp()) {
|
|
2383
|
+
const targetName = String(name || '').trim();
|
|
2384
|
+
const packages = this._listOmpPackages();
|
|
2385
|
+
const targetPackage = packages.find(pkg => pkg.name === targetName || pkg.installSource === targetName);
|
|
2386
|
+
const disabledEntries = this._listOmpDisabledPackageEntries();
|
|
2387
|
+
const disabled = new Set(disabledEntries.flatMap(item => [item.name, item.installSource].filter(Boolean)));
|
|
2388
|
+
if (enabled) {
|
|
2389
|
+
disabled.delete(targetName);
|
|
2390
|
+
if (targetPackage) {
|
|
2391
|
+
disabled.delete(targetPackage.name);
|
|
2392
|
+
disabled.delete(targetPackage.installSource);
|
|
2393
|
+
}
|
|
2394
|
+
} else {
|
|
2395
|
+
disabled.add(targetPackage || targetName);
|
|
2396
|
+
}
|
|
2397
|
+
this._setOmpDisabledPackages(Array.from(disabled));
|
|
2398
|
+
return {
|
|
2399
|
+
name: targetName,
|
|
2400
|
+
enabled,
|
|
2401
|
+
success: true
|
|
2402
|
+
};
|
|
2403
|
+
}
|
|
2404
|
+
|
|
1873
2405
|
if (this._isOpenCode()) {
|
|
1874
2406
|
const configured = this._listOpenCodeConfiguredPlugins();
|
|
1875
2407
|
const exists = configured.includes(name);
|
|
@@ -1963,6 +2495,19 @@ class PluginsService {
|
|
|
1963
2495
|
throw new Error(`${this.platform} plugin management is not supported`);
|
|
1964
2496
|
}
|
|
1965
2497
|
|
|
2498
|
+
if (this._isOmp()) {
|
|
2499
|
+
const settings = this._readOmpSettings();
|
|
2500
|
+
settings.packageConfig = settings.packageConfig && typeof settings.packageConfig === 'object' && !Array.isArray(settings.packageConfig)
|
|
2501
|
+
? settings.packageConfig
|
|
2502
|
+
: {};
|
|
2503
|
+
settings.packageConfig[name] = config;
|
|
2504
|
+
this._writeOmpSettings(settings);
|
|
2505
|
+
return {
|
|
2506
|
+
success: true,
|
|
2507
|
+
message: `Configuration updated for plugin "${name}"`
|
|
2508
|
+
};
|
|
2509
|
+
}
|
|
2510
|
+
|
|
1966
2511
|
if (this._isOpenCode()) {
|
|
1967
2512
|
const configDir = path.join(OPENCODE_CONFIG_DIR, 'plugins-config');
|
|
1968
2513
|
const configFile = resolvePluginConfigFile(configDir, name);
|
|
@@ -2798,6 +3343,13 @@ class PluginsService {
|
|
|
2798
3343
|
lspServers: data.lspServers || null,
|
|
2799
3344
|
commands: data.commands || [],
|
|
2800
3345
|
hooks: data.hooks || [],
|
|
3346
|
+
resourceTypes: normalizeOmpResourceTypes(data.resourceTypes || data.resources),
|
|
3347
|
+
resources: data.resources || null,
|
|
3348
|
+
containsSkills: Boolean(data.containsSkills),
|
|
3349
|
+
skillPaths: Array.isArray(data.skillPaths) ? data.skillPaths : [],
|
|
3350
|
+
pluginKind: data.pluginKind || (data.containsSkills ? 'skill-bundle' : 'plugin'),
|
|
3351
|
+
pluginType: data.pluginType || '',
|
|
3352
|
+
strict: data.strict,
|
|
2801
3353
|
isInstalled: false
|
|
2802
3354
|
};
|
|
2803
3355
|
}
|
|
@@ -2982,6 +3534,7 @@ class PluginsService {
|
|
|
2982
3534
|
const results = [];
|
|
2983
3535
|
for (const plugin of marketplace.plugins) {
|
|
2984
3536
|
const sourceInfo = this._repoFromMarketplaceSource(repo, plugin.source);
|
|
3537
|
+
const skillPaths = normalizeMarketplaceSkillPaths(plugin.skills);
|
|
2985
3538
|
const canReadManifest = sourceInfo.repo.provider === 'local' || sourceInfo.repo.id === repo.id;
|
|
2986
3539
|
const manifest = canReadManifest
|
|
2987
3540
|
? await this._readManifestFromRepo(sourceInfo.repo, sourceInfo.directory, [
|
|
@@ -3003,7 +3556,11 @@ class PluginsService {
|
|
|
3003
3556
|
marketplaceFormat: 'claude-marketplace',
|
|
3004
3557
|
lspServers: plugin.lspServers || null,
|
|
3005
3558
|
commands: manifest?.commands || [],
|
|
3006
|
-
hooks: manifest?.hooks || []
|
|
3559
|
+
hooks: manifest?.hooks || [],
|
|
3560
|
+
containsSkills: skillPaths.length > 0,
|
|
3561
|
+
skillPaths,
|
|
3562
|
+
pluginKind: skillPaths.length > 0 ? 'skill-bundle' : 'plugin',
|
|
3563
|
+
strict: Object.prototype.hasOwnProperty.call(plugin, 'strict') ? plugin.strict : undefined
|
|
3007
3564
|
}));
|
|
3008
3565
|
}
|
|
3009
3566
|
return results;
|
|
@@ -3041,6 +3598,96 @@ class PluginsService {
|
|
|
3041
3598
|
return results;
|
|
3042
3599
|
}
|
|
3043
3600
|
|
|
3601
|
+
_normalizeOmpCatalogEntries(catalog = null) {
|
|
3602
|
+
if (Array.isArray(catalog)) return catalog;
|
|
3603
|
+
if (!catalog || typeof catalog !== 'object') return [];
|
|
3604
|
+
for (const key of ['packages', 'plugins', 'extensions']) {
|
|
3605
|
+
if (Array.isArray(catalog[key])) return catalog[key];
|
|
3606
|
+
}
|
|
3607
|
+
return [];
|
|
3608
|
+
}
|
|
3609
|
+
|
|
3610
|
+
_normalizeOmpCatalogPackage(repo, entry = {}, catalog = {}, defaults = {}) {
|
|
3611
|
+
if (!entry || typeof entry !== 'object') return null;
|
|
3612
|
+
const installSource = String(
|
|
3613
|
+
entry.installSource ||
|
|
3614
|
+
entry.source ||
|
|
3615
|
+
entry.package ||
|
|
3616
|
+
entry.url ||
|
|
3617
|
+
entry.repo ||
|
|
3618
|
+
entry.repository ||
|
|
3619
|
+
entry.name ||
|
|
3620
|
+
''
|
|
3621
|
+
).trim();
|
|
3622
|
+
const name = String(entry.name || entry.id || entry.package || installSource || '').trim();
|
|
3623
|
+
if (!name || !installSource) return null;
|
|
3624
|
+
|
|
3625
|
+
const resourceTypes = normalizeOmpResourceTypes(
|
|
3626
|
+
entry.resourceTypes ||
|
|
3627
|
+
entry.resources ||
|
|
3628
|
+
entry.provides ||
|
|
3629
|
+
entry.omp?.resources ||
|
|
3630
|
+
defaults.resourceTypes
|
|
3631
|
+
);
|
|
3632
|
+
return this.buildMarketPluginItem(repo, {
|
|
3633
|
+
name,
|
|
3634
|
+
displayName: entry.displayName || entry.title || '',
|
|
3635
|
+
description: entry.description || '',
|
|
3636
|
+
author: entry.author || catalog.author || repo.owner,
|
|
3637
|
+
version: entry.version || 'latest',
|
|
3638
|
+
category: entry.category || 'general',
|
|
3639
|
+
directory: entry.directory || name,
|
|
3640
|
+
marketplace: entry.marketplace || repo.marketplace || catalog.name || defaults.marketplace || '',
|
|
3641
|
+
installSource,
|
|
3642
|
+
marketplaceFormat: defaults.marketplaceFormat || 'omp-package-catalog',
|
|
3643
|
+
pluginKind: 'package',
|
|
3644
|
+
pluginType: 'package',
|
|
3645
|
+
resourceTypes,
|
|
3646
|
+
resources: entry.resources || entry.provides || null,
|
|
3647
|
+
repoUrl: entry.repoUrl || entry.repositoryUrl || entry.repository || repo.repoUrl || buildRepoUrl(repo)
|
|
3648
|
+
});
|
|
3649
|
+
}
|
|
3650
|
+
|
|
3651
|
+
async _fetchOmpPackageCatalogPlugins(repo, fileMap, readJson) {
|
|
3652
|
+
if (!this._isOmp()) return [];
|
|
3653
|
+
const catalogFiles = ['omp-packages.json', '.omp/packages.json', 'packages.json'];
|
|
3654
|
+
for (const catalogPath of catalogFiles) {
|
|
3655
|
+
if (!fileMap.has(catalogPath)) continue;
|
|
3656
|
+
const catalog = await readJson(catalogPath);
|
|
3657
|
+
const entries = this._normalizeOmpCatalogEntries(catalog);
|
|
3658
|
+
const plugins = entries
|
|
3659
|
+
.map(entry => this._normalizeOmpCatalogPackage(repo, entry, catalog, {
|
|
3660
|
+
marketplaceFormat: 'omp-package-catalog'
|
|
3661
|
+
}))
|
|
3662
|
+
.filter(Boolean);
|
|
3663
|
+
if (plugins.length > 0) return plugins;
|
|
3664
|
+
}
|
|
3665
|
+
|
|
3666
|
+
const manifestPath = fileMap.has('omp.json') ? 'omp.json' : (fileMap.has('package.json') ? 'package.json' : '');
|
|
3667
|
+
if (!manifestPath) return [];
|
|
3668
|
+
const manifest = await readJson(manifestPath);
|
|
3669
|
+
const ompMeta = manifest.omp && typeof manifest.omp === 'object' ? manifest.omp: {};
|
|
3670
|
+
const installSource = ompMeta.installSource || manifest.installSource || manifest.name;
|
|
3671
|
+
const resourceTypes = normalizeOmpResourceTypes(
|
|
3672
|
+
ompMeta.resourceTypes ||
|
|
3673
|
+
ompMeta.resources ||
|
|
3674
|
+
manifest.resourceTypes ||
|
|
3675
|
+
manifest.resources
|
|
3676
|
+
);
|
|
3677
|
+
if (!installSource || resourceTypes.length === 0) return [];
|
|
3678
|
+
const plugin = this._normalizeOmpCatalogPackage(repo, {
|
|
3679
|
+
name: manifest.name || repo.name,
|
|
3680
|
+
installSource,
|
|
3681
|
+
version: manifest.version,
|
|
3682
|
+
description: manifest.description,
|
|
3683
|
+
author: manifest.author,
|
|
3684
|
+
resourceTypes
|
|
3685
|
+
}, { name: repo.marketplace || repo.name }, {
|
|
3686
|
+
marketplaceFormat: manifestPath === 'omp.json' ? 'omp-manifest' : 'omp-package-manifest'
|
|
3687
|
+
});
|
|
3688
|
+
return plugin ? [plugin] : [];
|
|
3689
|
+
}
|
|
3690
|
+
|
|
3044
3691
|
/**
|
|
3045
3692
|
* Get market plugins from configured repositories
|
|
3046
3693
|
* @returns {Promise<Array>} List of available market plugins
|
|
@@ -3117,6 +3764,15 @@ class PluginsService {
|
|
|
3117
3764
|
}
|
|
3118
3765
|
}
|
|
3119
3766
|
|
|
3767
|
+
// OMP package catalog format; legacy catalog filenames may still include omp.
|
|
3768
|
+
if (this._isOmp()) {
|
|
3769
|
+
const ompPackagePlugins = await this._fetchOmpPackageCatalogPlugins(repo, fileMap, readJson);
|
|
3770
|
+
if (ompPackagePlugins.length > 0) {
|
|
3771
|
+
marketPlugins.push(...ompPackagePlugins);
|
|
3772
|
+
continue;
|
|
3773
|
+
}
|
|
3774
|
+
}
|
|
3775
|
+
|
|
3120
3776
|
const nestedManifestFiles = files.filter(file => {
|
|
3121
3777
|
if (this._isCodex()) {
|
|
3122
3778
|
return file.path === '.codex-plugin/plugin.json' || file.path.endsWith('/.codex-plugin/plugin.json');
|
|
@@ -3162,7 +3818,12 @@ class PluginsService {
|
|
|
3162
3818
|
|
|
3163
3819
|
for (const dir of pluginDirs) {
|
|
3164
3820
|
try {
|
|
3165
|
-
const manifest =
|
|
3821
|
+
const manifest = this._isOmp()
|
|
3822
|
+
? await this._readManifestFromRepo(repo, dir, ['omp.json', 'extension.json', 'plugin.json', 'package.json'])
|
|
3823
|
+
: await readJson(`${dir}/plugin.json`);
|
|
3824
|
+
if (!manifest) {
|
|
3825
|
+
throw new Error(`File not found: ${dir}/plugin.json`);
|
|
3826
|
+
}
|
|
3166
3827
|
|
|
3167
3828
|
marketPlugins.push(this.buildMarketPluginItem(repo, {
|
|
3168
3829
|
name: manifest.name || dir,
|
|
@@ -3170,6 +3831,7 @@ class PluginsService {
|
|
|
3170
3831
|
author: manifest.author || repo.owner,
|
|
3171
3832
|
version: manifest.version || '1.0.0',
|
|
3172
3833
|
directory: dir,
|
|
3834
|
+
pluginKind: this._isOmp() ? 'extension' : undefined,
|
|
3173
3835
|
commands: manifest.commands || [],
|
|
3174
3836
|
hooks: manifest.hooks || []
|
|
3175
3837
|
}));
|