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
|
@@ -8,11 +8,13 @@ const path = require('path');
|
|
|
8
8
|
const AdmZip = require('adm-zip');
|
|
9
9
|
const toml = require('toml');
|
|
10
10
|
const tomlStringify = require('@iarna/toml').stringify;
|
|
11
|
+
const yaml = require('js-yaml');
|
|
11
12
|
const configTemplatesService = require('./config-templates-service');
|
|
12
13
|
const channelsService = require('./channels');
|
|
13
14
|
const codexChannelsService = require('./codex-channels');
|
|
14
15
|
const geminiChannelsService = require('./gemini-channels');
|
|
15
16
|
const opencodeChannelsService = require('./opencode-channels');
|
|
17
|
+
const ompChannelsService = require('./omp-channels');
|
|
16
18
|
const { AgentsService } = require('./agents-service');
|
|
17
19
|
const { CommandsService } = require('./commands-service');
|
|
18
20
|
const { SkillService } = require('./skill-service');
|
|
@@ -23,12 +25,16 @@ const CONFIG_VERSION = '1.4.0';
|
|
|
23
25
|
const SKILL_FILE_ENCODING = 'base64';
|
|
24
26
|
const SKILL_IGNORE_DIRS = new Set(['.git']);
|
|
25
27
|
const SKILL_IGNORE_FILES = new Set(['.DS_Store']);
|
|
28
|
+
const NATIVE_DIR_FILE_ENCODING = 'base64';
|
|
29
|
+
const NATIVE_DIR_IGNORE_DIRS = new Set(['.git']);
|
|
30
|
+
const NATIVE_DIR_IGNORE_FILES = new Set(['.DS_Store']);
|
|
26
31
|
const CC_TOOL_DIR = PATHS.base;
|
|
27
32
|
const LEGACY_CC_TOOL_DIR = PATHS.base;
|
|
28
33
|
const CLAUDE_SETTINGS_PATH = NATIVE_PATHS.claude.settings;
|
|
29
34
|
const LEGACY_PLUGINS_DIR = path.join(LEGACY_CC_TOOL_DIR, 'plugins', 'installed');
|
|
30
35
|
const LEGACY_PLUGINS_REGISTRY = path.join(LEGACY_CC_TOOL_DIR, 'plugins', 'registry.json');
|
|
31
|
-
const CLAUDE_PLUGINS_DIR =
|
|
36
|
+
const CLAUDE_PLUGINS_DIR = NATIVE_PATHS.claude.plugins
|
|
37
|
+
|| path.join(NATIVE_PATHS.claude.dir || path.dirname(NATIVE_PATHS.claude.settings), 'plugins');
|
|
32
38
|
const NATIVE_PLUGINS_REGISTRY = path.join(CLAUDE_PLUGINS_DIR, 'installed_plugins.json');
|
|
33
39
|
const PLUGIN_IGNORE_DIRS = new Set(['.git', 'node_modules', '.DS_Store']);
|
|
34
40
|
const PLUGIN_IGNORE_FILES = new Set(['.DS_Store']);
|
|
@@ -49,16 +55,59 @@ const LEGACY_UI_CONFIG_PATH = PATHS.uiConfig;
|
|
|
49
55
|
const LEGACY_NOTIFY_HOOK_PATH = PATHS.notifyHook;
|
|
50
56
|
const GEMINI_SETTINGS_PATH = path.join(path.dirname(NATIVE_PATHS.gemini.env), 'settings.json');
|
|
51
57
|
const AGENT_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode'];
|
|
52
|
-
const COMMAND_PLATFORMS = ['claude', 'gemini', 'opencode'];
|
|
53
|
-
const SKILL_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode'];
|
|
54
|
-
const PLUGIN_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode', '
|
|
58
|
+
const COMMAND_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode', 'omp'];
|
|
59
|
+
const SKILL_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode', 'omp'];
|
|
60
|
+
const PLUGIN_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode', 'omp'];
|
|
55
61
|
const CLAUDE_MARKETPLACES_REGISTRY = path.join(CLAUDE_PLUGINS_DIR, 'known_marketplaces.json');
|
|
56
62
|
const CODEX_PLUGINS_DIR = path.join(path.dirname(NATIVE_PATHS.codex.config), 'plugins');
|
|
57
63
|
const CODEX_PLUGINS_CACHE_DIR = path.join(CODEX_PLUGINS_DIR, 'cache');
|
|
58
64
|
const OPENCODE_PLUGINS_DIR = path.join(NATIVE_PATHS.opencode.config, 'plugins');
|
|
59
65
|
const OPENCODE_LEGACY_PLUGINS_DIR = path.join(NATIVE_PATHS.opencode.config, 'plugin');
|
|
60
|
-
const
|
|
61
|
-
const
|
|
66
|
+
const OMP_SETTINGS_PATH = NATIVE_PATHS.omp?.settings || path.join(PATHS.base, 'omp-config.yml');
|
|
67
|
+
const OMP_EXTENSIONS_DIR = NATIVE_PATHS.omp?.extensions || path.join(PATHS.base, 'omp-extensions');
|
|
68
|
+
|
|
69
|
+
function normalizeOmpResourceType(value = '') {
|
|
70
|
+
const key = String(value || '').trim().replace(/[\s_-]+/g, '').toLowerCase();
|
|
71
|
+
const map = {
|
|
72
|
+
extension: 'extension',
|
|
73
|
+
extensions: 'extension',
|
|
74
|
+
plugin: 'extension',
|
|
75
|
+
plugins: 'extension',
|
|
76
|
+
skill: 'skill',
|
|
77
|
+
skills: 'skill',
|
|
78
|
+
prompt: 'promptTemplate',
|
|
79
|
+
prompts: 'promptTemplate',
|
|
80
|
+
prompttemplate: 'promptTemplate',
|
|
81
|
+
prompttemplates: 'promptTemplate',
|
|
82
|
+
command: 'promptTemplate',
|
|
83
|
+
commands: 'promptTemplate',
|
|
84
|
+
theme: 'theme',
|
|
85
|
+
themes: 'theme',
|
|
86
|
+
mcp: 'mcp',
|
|
87
|
+
subagent: 'subagent',
|
|
88
|
+
subagents: 'subagent'
|
|
89
|
+
};
|
|
90
|
+
return map[key] || String(value || '').trim();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function normalizeOmpResourceTypes(input = []) {
|
|
94
|
+
const result = [];
|
|
95
|
+
const add = (value) => {
|
|
96
|
+
const normalized = normalizeOmpResourceType(value);
|
|
97
|
+
if (normalized && !result.includes(normalized)) result.push(normalized);
|
|
98
|
+
};
|
|
99
|
+
if (Array.isArray(input)) {
|
|
100
|
+
input.forEach(add);
|
|
101
|
+
} else if (input && typeof input === 'object') {
|
|
102
|
+
for (const [key, value] of Object.entries(input)) {
|
|
103
|
+
if (value === false || value == null) continue;
|
|
104
|
+
add(key);
|
|
105
|
+
}
|
|
106
|
+
} else if (input) {
|
|
107
|
+
add(input);
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
62
111
|
|
|
63
112
|
function getOpenCodeConfigPaths() {
|
|
64
113
|
try {
|
|
@@ -81,6 +130,7 @@ function getOpenCodeNotificationPluginPath() {
|
|
|
81
130
|
function getNativeConfigSpecs() {
|
|
82
131
|
const openCodeConfigPaths = getOpenCodeConfigPaths();
|
|
83
132
|
const openCodeNotificationPluginPath = getOpenCodeNotificationPluginPath();
|
|
133
|
+
const ompDir = NATIVE_PATHS.omp.dir || path.dirname(NATIVE_PATHS.omp.settings);
|
|
84
134
|
return {
|
|
85
135
|
claude: {
|
|
86
136
|
settings: { path: NATIVE_PATHS.claude.settings, format: 'json' }
|
|
@@ -100,6 +150,19 @@ function getNativeConfigSpecs() {
|
|
|
100
150
|
...(openCodeNotificationPluginPath
|
|
101
151
|
? { codingToolNotifyPlugin: { path: openCodeNotificationPluginPath, format: 'text' } }
|
|
102
152
|
: {})
|
|
153
|
+
},
|
|
154
|
+
omp: {
|
|
155
|
+
settings: { path: NATIVE_PATHS.omp.settings, format: 'yaml' },
|
|
156
|
+
auth: { path: NATIVE_PATHS.omp.auth, format: 'json', mode: 0o600 },
|
|
157
|
+
models: { path: NATIVE_PATHS.omp.models, format: 'yaml' },
|
|
158
|
+
commands: { path: NATIVE_PATHS.omp.commands || path.join(ompDir, 'commands'), format: 'directory' },
|
|
159
|
+
prompts: { path: NATIVE_PATHS.omp.prompts, format: 'directory' },
|
|
160
|
+
skills: { path: NATIVE_PATHS.omp.skills, format: 'directory' },
|
|
161
|
+
extensions: { path: NATIVE_PATHS.omp.extensions, format: 'directory' },
|
|
162
|
+
themes: { path: NATIVE_PATHS.omp.themes || path.join(ompDir, 'themes'), format: 'directory' },
|
|
163
|
+
packages: { path: NATIVE_PATHS.omp.packages || path.join(ompDir, 'packages'), format: 'directory' },
|
|
164
|
+
npmPackages: { path: path.join(ompDir, 'npm'), format: 'directory' },
|
|
165
|
+
gitPackages: { path: path.join(ompDir, 'git'), format: 'directory' }
|
|
103
166
|
}
|
|
104
167
|
};
|
|
105
168
|
}
|
|
@@ -120,6 +183,17 @@ function readJsonFileSafe(filePath) {
|
|
|
120
183
|
}
|
|
121
184
|
}
|
|
122
185
|
|
|
186
|
+
function readYamlFileSafe(filePath) {
|
|
187
|
+
if (!filePath || !fs.existsSync(filePath)) return null;
|
|
188
|
+
try {
|
|
189
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
190
|
+
const parsed = yaml.load(content);
|
|
191
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
|
|
192
|
+
} catch (err) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
123
197
|
function readTextFileSafe(filePath) {
|
|
124
198
|
if (!filePath || !fs.existsSync(filePath)) return null;
|
|
125
199
|
try {
|
|
@@ -135,6 +209,10 @@ function readNativeConfigSnapshot(spec) {
|
|
|
135
209
|
}
|
|
136
210
|
|
|
137
211
|
try {
|
|
212
|
+
if (spec.format === 'directory') {
|
|
213
|
+
return readNativeDirectorySnapshot(spec.path);
|
|
214
|
+
}
|
|
215
|
+
|
|
138
216
|
const rawContent = fs.readFileSync(spec.path, 'utf8');
|
|
139
217
|
if (spec.format === 'json') {
|
|
140
218
|
try {
|
|
@@ -152,6 +230,22 @@ function readNativeConfigSnapshot(spec) {
|
|
|
152
230
|
}
|
|
153
231
|
}
|
|
154
232
|
|
|
233
|
+
if (spec.format === 'yaml') {
|
|
234
|
+
try {
|
|
235
|
+
return {
|
|
236
|
+
format: 'yaml',
|
|
237
|
+
fileName: path.basename(spec.path),
|
|
238
|
+
content: yaml.load(rawContent) || {}
|
|
239
|
+
};
|
|
240
|
+
} catch (err) {
|
|
241
|
+
return {
|
|
242
|
+
format: 'text',
|
|
243
|
+
fileName: path.basename(spec.path),
|
|
244
|
+
content: rawContent
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
155
249
|
return {
|
|
156
250
|
format: spec.format || 'text',
|
|
157
251
|
fileName: path.basename(spec.path),
|
|
@@ -162,6 +256,61 @@ function readNativeConfigSnapshot(spec) {
|
|
|
162
256
|
}
|
|
163
257
|
}
|
|
164
258
|
|
|
259
|
+
function collectNativeDirectoryFiles(baseDir) {
|
|
260
|
+
const files = [];
|
|
261
|
+
const stack = [baseDir];
|
|
262
|
+
|
|
263
|
+
while (stack.length > 0) {
|
|
264
|
+
const currentDir = stack.pop();
|
|
265
|
+
let entries = [];
|
|
266
|
+
try {
|
|
267
|
+
entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
268
|
+
} catch (err) {
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
for (const entry of entries) {
|
|
273
|
+
if (entry.isDirectory()) {
|
|
274
|
+
if (NATIVE_DIR_IGNORE_DIRS.has(entry.name)) {
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
stack.push(path.join(currentDir, entry.name));
|
|
278
|
+
} else if (entry.isFile()) {
|
|
279
|
+
if (NATIVE_DIR_IGNORE_FILES.has(entry.name)) {
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
283
|
+
const relativePath = path.relative(baseDir, fullPath);
|
|
284
|
+
try {
|
|
285
|
+
const content = fs.readFileSync(fullPath);
|
|
286
|
+
files.push({
|
|
287
|
+
path: relativePath,
|
|
288
|
+
encoding: NATIVE_DIR_FILE_ENCODING,
|
|
289
|
+
content: content.toString(NATIVE_DIR_FILE_ENCODING)
|
|
290
|
+
});
|
|
291
|
+
} catch (err) {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
files.sort((a, b) => a.path.localeCompare(b.path));
|
|
299
|
+
return files;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function readNativeDirectorySnapshot(dirPath) {
|
|
303
|
+
const files = collectNativeDirectoryFiles(dirPath);
|
|
304
|
+
if (files.length === 0) {
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
return {
|
|
308
|
+
format: 'directory',
|
|
309
|
+
fileName: path.basename(dirPath),
|
|
310
|
+
files
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
165
314
|
function writeJsonFileAbsolute(filePath, data, overwrite, options = {}) {
|
|
166
315
|
if (data === undefined) {
|
|
167
316
|
return 'failed';
|
|
@@ -179,6 +328,18 @@ function writeJsonFileAbsolute(filePath, data, overwrite, options = {}) {
|
|
|
179
328
|
return 'success';
|
|
180
329
|
}
|
|
181
330
|
|
|
331
|
+
function writeYamlFileAbsolute(filePath, data, overwrite, options = {}) {
|
|
332
|
+
if (data === undefined) {
|
|
333
|
+
return 'failed';
|
|
334
|
+
}
|
|
335
|
+
return writeTextFileAbsolute(
|
|
336
|
+
filePath,
|
|
337
|
+
yaml.dump(data || {}, { lineWidth: 120, noRefs: true, sortKeys: false }),
|
|
338
|
+
overwrite,
|
|
339
|
+
options
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
|
|
182
343
|
function writeTextFileAbsolute(filePath, content, overwrite, options = {}) {
|
|
183
344
|
if (content === undefined || content === null) {
|
|
184
345
|
return 'failed';
|
|
@@ -198,6 +359,9 @@ function writeTextFileAbsolute(filePath, content, overwrite, options = {}) {
|
|
|
198
359
|
|
|
199
360
|
function writeNativeConfigAbsolute(spec, entry, overwrite) {
|
|
200
361
|
if (!spec?.path || !entry || entry.content === undefined) {
|
|
362
|
+
if (spec?.format === 'directory' && entry?.files !== undefined) {
|
|
363
|
+
return writeNativeDirectoryAbsolute(spec.path, entry.files, overwrite);
|
|
364
|
+
}
|
|
201
365
|
return 'failed';
|
|
202
366
|
}
|
|
203
367
|
|
|
@@ -205,10 +369,56 @@ function writeNativeConfigAbsolute(spec, entry, overwrite) {
|
|
|
205
369
|
if (format === 'json' && entry.content && typeof entry.content === 'object') {
|
|
206
370
|
return writeJsonFileAbsolute(spec.path, entry.content, overwrite, { mode: spec.mode });
|
|
207
371
|
}
|
|
372
|
+
if (format === 'yaml' && entry.content && typeof entry.content === 'object') {
|
|
373
|
+
return writeTextFileAbsolute(
|
|
374
|
+
spec.path,
|
|
375
|
+
yaml.dump(entry.content, { lineWidth: 120, noRefs: true, sortKeys: false }),
|
|
376
|
+
overwrite,
|
|
377
|
+
{ mode: spec.mode }
|
|
378
|
+
);
|
|
379
|
+
}
|
|
208
380
|
|
|
209
381
|
return writeTextFileAbsolute(spec.path, String(entry.content), overwrite, { mode: spec.mode });
|
|
210
382
|
}
|
|
211
383
|
|
|
384
|
+
function writeNativeDirectoryAbsolute(dirPath, files = [], overwrite) {
|
|
385
|
+
if (!dirPath || !Array.isArray(files)) {
|
|
386
|
+
return 'failed';
|
|
387
|
+
}
|
|
388
|
+
if (files.length === 0) {
|
|
389
|
+
return 'skipped';
|
|
390
|
+
}
|
|
391
|
+
if (fs.existsSync(dirPath) && !overwrite) {
|
|
392
|
+
return 'skipped';
|
|
393
|
+
}
|
|
394
|
+
if (fs.existsSync(dirPath)) {
|
|
395
|
+
fs.rmSync(dirPath, { recursive: true, force: true });
|
|
396
|
+
}
|
|
397
|
+
ensureDir(dirPath);
|
|
398
|
+
|
|
399
|
+
let failed = false;
|
|
400
|
+
for (const file of files) {
|
|
401
|
+
const filePath = resolveSafePath(dirPath, file.path);
|
|
402
|
+
if (!filePath) {
|
|
403
|
+
failed = true;
|
|
404
|
+
break;
|
|
405
|
+
}
|
|
406
|
+
try {
|
|
407
|
+
ensureDir(path.dirname(filePath));
|
|
408
|
+
if (file.encoding === NATIVE_DIR_FILE_ENCODING || file.encoding === SKILL_FILE_ENCODING) {
|
|
409
|
+
fs.writeFileSync(filePath, Buffer.from(file.content || '', file.encoding));
|
|
410
|
+
} else {
|
|
411
|
+
fs.writeFileSync(filePath, file.content || '', file.encoding || 'utf8');
|
|
412
|
+
}
|
|
413
|
+
} catch (err) {
|
|
414
|
+
failed = true;
|
|
415
|
+
break;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
return failed ? 'failed' : 'success';
|
|
420
|
+
}
|
|
421
|
+
|
|
212
422
|
function getConfigFilePath() {
|
|
213
423
|
try {
|
|
214
424
|
const { getConfigFilePath: resolveConfigPath } = require('../../config/loader');
|
|
@@ -231,7 +441,7 @@ function buildExportReadme(exportData) {
|
|
|
231
441
|
- 插件 (Plugins)
|
|
232
442
|
- MCP 服务器配置
|
|
233
443
|
- OAuth 凭证管理池
|
|
234
|
-
- 各平台原生配置(Claude / Codex / Gemini / OpenCode)
|
|
444
|
+
- 各平台原生配置(Claude / Codex / Gemini / OpenCode / OMP)
|
|
235
445
|
- UI 配置(主题、面板显示、排序等)
|
|
236
446
|
- Prompts 预设
|
|
237
447
|
- 安全配置
|
|
@@ -878,6 +1088,8 @@ function exportOpenCodePluginsByPlatform(service) {
|
|
|
878
1088
|
pluginKind: plugin.pluginKind || 'plugin',
|
|
879
1089
|
name: plugin.name,
|
|
880
1090
|
directory: plugin.directory || plugin.name,
|
|
1091
|
+
installSource: plugin.installSource || plugin.source || plugin.name,
|
|
1092
|
+
resourceTypes: normalizeOmpResourceTypes(plugin.resourceTypes || plugin.resources),
|
|
881
1093
|
version: plugin.version || 'latest',
|
|
882
1094
|
description: plugin.description || '',
|
|
883
1095
|
enabled: plugin.enabled !== false,
|
|
@@ -896,13 +1108,13 @@ function exportOpenCodePluginsByPlatform(service) {
|
|
|
896
1108
|
return { plugins, control };
|
|
897
1109
|
}
|
|
898
1110
|
|
|
899
|
-
function
|
|
1111
|
+
function exportOmpPluginsByPlatform(service) {
|
|
900
1112
|
const plugins = (service.listPlugins().plugins || [])
|
|
901
1113
|
.map((plugin) => {
|
|
902
|
-
if (plugin.pluginType === 'package' || plugin.source === '
|
|
1114
|
+
if (plugin.pluginType === 'package' || plugin.source === 'omp-settings') {
|
|
903
1115
|
return {
|
|
904
|
-
platform: '
|
|
905
|
-
type: '
|
|
1116
|
+
platform: 'omp',
|
|
1117
|
+
type: 'omp-package',
|
|
906
1118
|
pluginType: 'package',
|
|
907
1119
|
pluginKind: plugin.pluginKind || 'package',
|
|
908
1120
|
name: plugin.name,
|
|
@@ -911,22 +1123,18 @@ function exportPiPluginsByPlatform(service) {
|
|
|
911
1123
|
description: plugin.description || '',
|
|
912
1124
|
enabled: plugin.enabled !== false,
|
|
913
1125
|
installed: plugin.installed !== false,
|
|
914
|
-
source: plugin.source || '
|
|
1126
|
+
source: plugin.source || 'omp-settings'
|
|
915
1127
|
};
|
|
916
1128
|
}
|
|
917
|
-
return buildManagedPluginExportItem(plugin, '
|
|
918
|
-
type: '
|
|
1129
|
+
return buildManagedPluginExportItem(plugin, 'omp', OMP_EXTENSIONS_DIR, {
|
|
1130
|
+
type: 'omp-extension',
|
|
919
1131
|
pluginType: plugin.pluginType || 'extension',
|
|
920
1132
|
pluginKind: plugin.pluginKind || 'extension',
|
|
921
|
-
manifestCandidates: ['
|
|
1133
|
+
manifestCandidates: ['omp.json', 'extension.json', 'plugin.json', 'package.json']
|
|
922
1134
|
});
|
|
923
1135
|
})
|
|
924
1136
|
.filter(Boolean);
|
|
925
|
-
const control = exportPluginControlSnapshot('
|
|
926
|
-
const piSettings = readNativeConfigSnapshot({ path: PI_SETTINGS_PATH, format: 'json' });
|
|
927
|
-
if (piSettings) {
|
|
928
|
-
control.nativeSettings = piSettings;
|
|
929
|
-
}
|
|
1137
|
+
const control = exportPluginControlSnapshot('omp', service);
|
|
930
1138
|
return { plugins, control };
|
|
931
1139
|
}
|
|
932
1140
|
|
|
@@ -940,8 +1148,8 @@ function exportPluginsSnapshotByPlatform() {
|
|
|
940
1148
|
result[platform] = exportCodexPluginsByPlatform(service);
|
|
941
1149
|
} else if (platform === 'opencode') {
|
|
942
1150
|
result[platform] = exportOpenCodePluginsByPlatform(service);
|
|
943
|
-
} else if (platform === '
|
|
944
|
-
result[platform] =
|
|
1151
|
+
} else if (platform === 'omp') {
|
|
1152
|
+
result[platform] = exportOmpPluginsByPlatform(service);
|
|
945
1153
|
} else {
|
|
946
1154
|
result[platform] = {
|
|
947
1155
|
plugins: service.listPlugins().plugins || [],
|
|
@@ -1307,33 +1515,68 @@ function writeOpenCodePluginConfig(packages = [], overwrite = true) {
|
|
|
1307
1515
|
return writeJsonFileAbsolute(configPath, { ...existing, plugin: mergedPlugins }, true);
|
|
1308
1516
|
}
|
|
1309
1517
|
|
|
1310
|
-
function
|
|
1518
|
+
function writeOmpPluginSettings(plugins = [], snapshot = {}, overwrite = true) {
|
|
1311
1519
|
const nativeSettings = snapshot.control?.nativeSettings;
|
|
1312
1520
|
if (nativeSettings?.content !== undefined) {
|
|
1313
|
-
return writeNativeConfigAbsolute({ path:
|
|
1521
|
+
return writeNativeConfigAbsolute({ path: OMP_SETTINGS_PATH, format: 'yaml' }, {
|
|
1522
|
+
...nativeSettings,
|
|
1523
|
+
format: 'yaml'
|
|
1524
|
+
}, overwrite);
|
|
1314
1525
|
}
|
|
1315
1526
|
|
|
1316
|
-
const settings =
|
|
1317
|
-
if (fs.existsSync(
|
|
1527
|
+
const settings = readYamlFileSafe(OMP_SETTINGS_PATH) || {};
|
|
1528
|
+
if (fs.existsSync(OMP_SETTINGS_PATH) && !overwrite) {
|
|
1318
1529
|
return 'skipped';
|
|
1319
1530
|
}
|
|
1320
1531
|
const existingPackages = Array.isArray(settings.packages) ? settings.packages : [];
|
|
1321
1532
|
const existingDisabled = Array.isArray(settings.disabledPackages) ? settings.disabledPackages : [];
|
|
1322
|
-
const packagePlugins = plugins.filter(plugin => plugin.type === '
|
|
1323
|
-
const
|
|
1533
|
+
const packagePlugins = plugins.filter(plugin => plugin.type === 'omp-package' || plugin.pluginType === 'package');
|
|
1534
|
+
const packageIdentity = (item) => {
|
|
1535
|
+
if (typeof item === 'string') return item;
|
|
1536
|
+
if (!item || typeof item !== 'object') return '';
|
|
1537
|
+
return item.name || item.installSource || item.source || '';
|
|
1538
|
+
};
|
|
1539
|
+
const buildPackageEntry = (plugin) => {
|
|
1540
|
+
const name = plugin.name || plugin.directory || plugin.installSource || '';
|
|
1541
|
+
if (!name) return null;
|
|
1542
|
+
const installSource = plugin.installSource || plugin.packageSource || '';
|
|
1543
|
+
const resourceTypes = normalizeOmpResourceTypes(plugin.resourceTypes || plugin.resources);
|
|
1544
|
+
if (!installSource || installSource === name) {
|
|
1545
|
+
if (resourceTypes.length === 0 && !plugin.version && !plugin.description) return name;
|
|
1546
|
+
}
|
|
1547
|
+
return {
|
|
1548
|
+
name,
|
|
1549
|
+
...(installSource ? { source: installSource, installSource } : {}),
|
|
1550
|
+
...(plugin.version ? { version: plugin.version } : {}),
|
|
1551
|
+
...(plugin.description ? { description: plugin.description } : {}),
|
|
1552
|
+
...(resourceTypes.length > 0 ? { resourceTypes } : {})
|
|
1553
|
+
};
|
|
1554
|
+
};
|
|
1555
|
+
const mergePackageEntries = (current, additions) => {
|
|
1556
|
+
const result = [];
|
|
1557
|
+
const seen = new Set();
|
|
1558
|
+
for (const item of [...current, ...additions]) {
|
|
1559
|
+
const identity = packageIdentity(item);
|
|
1560
|
+
if (!identity || seen.has(identity)) continue;
|
|
1561
|
+
seen.add(identity);
|
|
1562
|
+
result.push(item);
|
|
1563
|
+
}
|
|
1564
|
+
return result;
|
|
1565
|
+
};
|
|
1566
|
+
const packages = packagePlugins.map(buildPackageEntry).filter(Boolean);
|
|
1324
1567
|
const disabledPackages = packagePlugins
|
|
1325
1568
|
.filter(plugin => plugin.enabled === false)
|
|
1326
|
-
.map(
|
|
1569
|
+
.map(buildPackageEntry)
|
|
1327
1570
|
.filter(Boolean);
|
|
1328
1571
|
|
|
1329
1572
|
if (packages.length === 0 && disabledPackages.length === 0) {
|
|
1330
1573
|
return 'skipped';
|
|
1331
1574
|
}
|
|
1332
1575
|
|
|
1333
|
-
return
|
|
1576
|
+
return writeYamlFileAbsolute(OMP_SETTINGS_PATH, {
|
|
1334
1577
|
...settings,
|
|
1335
|
-
packages:
|
|
1336
|
-
disabledPackages:
|
|
1578
|
+
packages: mergePackageEntries(existingPackages, packages),
|
|
1579
|
+
disabledPackages: mergePackageEntries(existingDisabled, disabledPackages)
|
|
1337
1580
|
}, true);
|
|
1338
1581
|
}
|
|
1339
1582
|
|
|
@@ -1419,8 +1662,8 @@ function importPluginsByPlatformSnapshot(snapshotByPlatform = {}, legacyPlugins
|
|
|
1419
1662
|
.map(plugin => plugin.name || plugin.directory)
|
|
1420
1663
|
.filter(Boolean);
|
|
1421
1664
|
applyImportStatus(results, writeOpenCodePluginConfig(packages, overwrite));
|
|
1422
|
-
} else if (platform === '
|
|
1423
|
-
applyImportStatus(results,
|
|
1665
|
+
} else if (platform === 'omp' && (hasControl || plugins.length > 0)) {
|
|
1666
|
+
applyImportStatus(results, writeOmpPluginSettings(plugins, snapshot, overwrite));
|
|
1424
1667
|
}
|
|
1425
1668
|
|
|
1426
1669
|
for (const plugin of plugins) {
|
|
@@ -1432,11 +1675,11 @@ function importPluginsByPlatformSnapshot(snapshotByPlatform = {}, legacyPlugins
|
|
|
1432
1675
|
continue;
|
|
1433
1676
|
}
|
|
1434
1677
|
applyImportStatus(results, importPluginToDirectory(platform, plugin, getOpenCodePluginsDir(), overwrite));
|
|
1435
|
-
} else if (platform === '
|
|
1436
|
-
if (plugin.type === '
|
|
1678
|
+
} else if (platform === 'omp') {
|
|
1679
|
+
if (plugin.type === 'omp-package' || plugin.pluginType === 'package') {
|
|
1437
1680
|
continue;
|
|
1438
1681
|
}
|
|
1439
|
-
applyImportStatus(results, importPluginToDirectory(platform, plugin,
|
|
1682
|
+
applyImportStatus(results, importPluginToDirectory(platform, plugin, OMP_EXTENSIONS_DIR, overwrite));
|
|
1440
1683
|
} else if (platform === 'claude') {
|
|
1441
1684
|
const isLegacy = plugin.type === 'legacy';
|
|
1442
1685
|
applyImportStatus(results, importPluginToDirectory(
|
|
@@ -1507,7 +1750,8 @@ function getAllChannelsByType() {
|
|
|
1507
1750
|
const codex = codexChannelsService.getChannels()?.channels || [];
|
|
1508
1751
|
const gemini = geminiChannelsService.getChannels()?.channels || [];
|
|
1509
1752
|
const opencode = opencodeChannelsService.getChannels()?.channels || [];
|
|
1510
|
-
|
|
1753
|
+
const omp = ompChannelsService.getChannels()?.channels || [];
|
|
1754
|
+
return { claude, codex, gemini, opencode, omp };
|
|
1511
1755
|
}
|
|
1512
1756
|
|
|
1513
1757
|
/**
|
|
@@ -1718,7 +1962,8 @@ async function importConfigs(importData, options = {}) {
|
|
|
1718
1962
|
: (Array.isArray(channels) ? channels : []),
|
|
1719
1963
|
codex: hasTypedChannels && Array.isArray(channelsByType.codex) ? channelsByType.codex : [],
|
|
1720
1964
|
gemini: hasTypedChannels && Array.isArray(channelsByType.gemini) ? channelsByType.gemini : [],
|
|
1721
|
-
opencode: hasTypedChannels && Array.isArray(channelsByType.opencode) ? channelsByType.opencode : []
|
|
1965
|
+
opencode: hasTypedChannels && Array.isArray(channelsByType.opencode) ? channelsByType.opencode : [],
|
|
1966
|
+
omp: hasTypedChannels && Array.isArray(channelsByType.omp) ? channelsByType.omp: []
|
|
1722
1967
|
};
|
|
1723
1968
|
|
|
1724
1969
|
// 导入配置模板
|
|
@@ -1815,6 +2060,18 @@ async function importConfigs(importData, options = {}) {
|
|
|
1815
2060
|
(channel.name && channel.baseUrl && c.name === channel.name && c.baseUrl === channel.baseUrl)
|
|
1816
2061
|
));
|
|
1817
2062
|
|
|
2063
|
+
importTypedChannels('omp', ompChannelsService, channel => {
|
|
2064
|
+
const { name, baseUrl, apiKey, ...extraConfig } = channel;
|
|
2065
|
+
ompChannelsService.createChannel(name, baseUrl, apiKey, extraConfig);
|
|
2066
|
+
}, (existingChannels, channel) => existingChannels.find(c =>
|
|
2067
|
+
(channel.id && c.id === channel.id) ||
|
|
2068
|
+
(channel.providerKey && c.providerKey === channel.providerKey) ||
|
|
2069
|
+
(channel.name && channel.baseUrl && c.name === channel.name && c.baseUrl === channel.baseUrl)
|
|
2070
|
+
));
|
|
2071
|
+
if ((importChannelsByType.omp || []).length > 0 && typeof ompChannelsService.syncManagedProviderExtension === 'function') {
|
|
2072
|
+
ompChannelsService.syncManagedProviderExtension();
|
|
2073
|
+
}
|
|
2074
|
+
|
|
1818
2075
|
// 导入工作区配置
|
|
1819
2076
|
if (workspaces && overwrite) {
|
|
1820
2077
|
try {
|
|
@@ -17,33 +17,32 @@ const REGISTRY_FILE = PATHS.configRegistry;
|
|
|
17
17
|
const CONFIGS_DIR = PATHS.configs;
|
|
18
18
|
|
|
19
19
|
// Claude Code native directories
|
|
20
|
-
const CLAUDE_HOME_DIR = path.dirname(NATIVE_PATHS.claude.settings);
|
|
20
|
+
const CLAUDE_HOME_DIR = NATIVE_PATHS.claude.dir || path.dirname(NATIVE_PATHS.claude.settings);
|
|
21
21
|
const CLAUDE_DIRS = {
|
|
22
|
-
skills: path.join(CLAUDE_HOME_DIR, 'skills'),
|
|
23
|
-
commands: path.join(CLAUDE_HOME_DIR, 'commands'),
|
|
24
|
-
agents: path.join(CLAUDE_HOME_DIR, 'agents'),
|
|
25
|
-
plugins: path.join(CLAUDE_HOME_DIR, 'plugins')
|
|
22
|
+
skills: NATIVE_PATHS.claude.skills || path.join(CLAUDE_HOME_DIR, 'skills'),
|
|
23
|
+
commands: NATIVE_PATHS.claude.commands || path.join(CLAUDE_HOME_DIR, 'commands'),
|
|
24
|
+
agents: NATIVE_PATHS.claude.agents || path.join(CLAUDE_HOME_DIR, 'agents'),
|
|
25
|
+
plugins: NATIVE_PATHS.claude.plugins || path.join(CLAUDE_HOME_DIR, 'plugins')
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
// Valid config types
|
|
29
29
|
const CONFIG_TYPES = ['skills', 'commands', 'agents', 'plugins'];
|
|
30
|
-
const SUPPORTED_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode'];
|
|
30
|
+
const SUPPORTED_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode', 'omp'];
|
|
31
31
|
|
|
32
32
|
const PLATFORM_SUPPORT = {
|
|
33
|
-
skills: { claude: true, codex: true, gemini: true, opencode: true },
|
|
34
|
-
commands: { claude: true, codex: true, gemini: true, opencode: true },
|
|
35
|
-
agents: { claude: true, codex: true, gemini: true, opencode: true },
|
|
36
|
-
plugins: { claude: true, codex: false, gemini: false, opencode: true }
|
|
33
|
+
skills: { claude: true, codex: true, gemini: true, opencode: true, omp: true },
|
|
34
|
+
commands: { claude: true, codex: true, gemini: true, opencode: true, omp: true },
|
|
35
|
+
agents: { claude: true, codex: true, gemini: true, opencode: true, omp: false },
|
|
36
|
+
plugins: { claude: true, codex: false, gemini: false, opencode: true, omp: true }
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
function normalizePlatforms(type, platforms = {}) {
|
|
40
40
|
const support = PLATFORM_SUPPORT[type] || {};
|
|
41
|
-
const normalized = {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
};
|
|
41
|
+
const normalized = {};
|
|
42
|
+
|
|
43
|
+
for (const platform of SUPPORTED_PLATFORMS) {
|
|
44
|
+
normalized[platform] = !!platforms?.[platform];
|
|
45
|
+
}
|
|
47
46
|
|
|
48
47
|
for (const platform of SUPPORTED_PLATFORMS) {
|
|
49
48
|
if (support[platform] === false) {
|
|
@@ -585,7 +584,8 @@ class ConfigRegistryService {
|
|
|
585
584
|
claude: 0,
|
|
586
585
|
codex: 0,
|
|
587
586
|
gemini: 0,
|
|
588
|
-
opencode: 0
|
|
587
|
+
opencode: 0,
|
|
588
|
+
omp: 0
|
|
589
589
|
}
|
|
590
590
|
};
|
|
591
591
|
|
|
@@ -598,7 +598,8 @@ class ConfigRegistryService {
|
|
|
598
598
|
claude: items.filter(i => i.platforms?.claude).length,
|
|
599
599
|
codex: items.filter(i => i.platforms?.codex).length,
|
|
600
600
|
gemini: items.filter(i => i.platforms?.gemini).length,
|
|
601
|
-
opencode: items.filter(i => i.platforms?.opencode).length
|
|
601
|
+
opencode: items.filter(i => i.platforms?.opencode).length,
|
|
602
|
+
omp: items.filter(i => i.platforms?.omp).length
|
|
602
603
|
};
|
|
603
604
|
|
|
604
605
|
stats.byType[type] = typeStats;
|
|
@@ -607,6 +608,7 @@ class ConfigRegistryService {
|
|
|
607
608
|
stats.byPlatform.codex += typeStats.codex;
|
|
608
609
|
stats.byPlatform.gemini += typeStats.gemini;
|
|
609
610
|
stats.byPlatform.opencode += typeStats.opencode;
|
|
611
|
+
stats.byPlatform.omp += typeStats.omp;
|
|
610
612
|
}
|
|
611
613
|
|
|
612
614
|
return stats;
|