coding-tool-x 3.7.0 → 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 +5 -6
- package/dist/web/assets/{Analytics-Dma_j2Rq.js → Analytics-Dpje9L84.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-C49Y1PLH.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-B1ECTHyY.js → PluginManager-DsN-xNXx.js} +1 -1
- package/dist/web/assets/ProjectList-4BCObimU.js +1 -0
- package/dist/web/assets/{ProjectList-B_L55-l9.css → ProjectList-D3a0oRum.css} +1 -1
- package/dist/web/assets/{SessionList-CH5GwwiJ.js → SessionList-D4c8FRzq.js} +1 -1
- package/dist/web/assets/{SkillManager-CRyVhjYQ.js → SkillManager-C-KYbXB5.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-CO9tclVt.js → WorkspaceManager-B-BlPJHX.js} +1 -1
- package/dist/web/assets/index-Btfvh0GG.js +2 -0
- package/dist/web/assets/{index-CM26UrnJ.css → index-CLNa6DhH.css} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +2 -1
- package/src/commands/channels.js +8 -8
- package/src/commands/daemon.js +4 -4
- package/src/commands/doctor.js +1 -1
- package/src/commands/logs.js +1 -3
- package/src/commands/port-config.js +4 -4
- package/src/commands/proxy-control.js +13 -13
- package/src/commands/stats.js +6 -6
- package/src/commands/toggle-proxy.js +8 -8
- package/src/config/default.js +3 -3
- package/src/config/paths.js +46 -49
- package/src/index.js +4 -5
- package/src/server/api/commands.js +1 -1
- package/src/server/api/config-export.js +2 -2
- package/src/server/api/config-registry.js +1 -1
- package/src/server/api/config.js +1 -1
- package/src/server/api/dashboard.js +16 -16
- package/src/server/api/mcp.js +2 -2
- package/src/server/api/{pi-channels.js → omp-channels.js} +15 -15
- package/src/server/api/{pi-config.js → omp-config.js} +13 -13
- package/src/server/api/{pi-projects.js → omp-projects.js} +5 -5
- package/src/server/api/{pi-proxy.js → omp-proxy.js} +18 -18
- package/src/server/api/{pi-sessions.js → omp-sessions.js} +21 -21
- package/src/server/api/{pi-statistics.js → omp-statistics.js} +1 -1
- package/src/server/api/plugins.js +1 -1
- package/src/server/api/skills.js +1 -1
- package/src/server/api/workspaces.js +1 -1
- package/src/server/index.js +10 -10
- package/src/server/{pi-proxy-server.js → omp-proxy-server.js} +13 -13
- package/src/server/services/channel-balance.js +3 -3
- package/src/server/services/channel-scheduler.js +4 -4
- package/src/server/services/commands-service.js +5 -5
- package/src/server/services/config-export-service.js +53 -53
- package/src/server/services/config-registry-service.js +8 -8
- package/src/server/services/config-sync-manager.js +26 -26
- package/src/server/services/config-templates-service.js +28 -28
- package/src/server/services/mcp-service.js +20 -20
- package/src/server/services/notification-hooks.js +138 -6
- package/src/server/services/{pi-auth-providers.js → omp-auth-providers.js} +2 -2
- package/src/server/services/{pi-channels.js → omp-channels.js} +5 -5
- package/src/server/services/{pi-config.js → omp-config.js} +47 -65
- package/src/server/services/{pi-sessions.js → omp-sessions.js} +20 -20
- package/src/server/services/{pi-settings-manager.js → omp-settings-manager.js} +422 -18
- package/src/server/services/{pi-statistics-service.js → omp-statistics-service.js} +2 -2
- package/src/server/services/plugins-service.js +122 -122
- package/src/server/services/prompts-service.js +20 -20
- package/src/server/services/proxy-log-helper.js +1 -1
- package/src/server/services/proxy-runtime.js +1 -1
- package/src/server/services/skill-service.js +7 -7
- package/src/server/services/speed-test.js +29 -29
- package/src/server/services/ui-config.js +3 -3
- package/src/server/services/workspace-service.js +8 -8
- package/src/server/websocket-server.js +4 -4
- package/src/shared/platforms.js +201 -0
- package/dist/web/assets/Home-DGGC8H4g.js +0 -1
- package/dist/web/assets/Home-ewgeIhF7.css +0 -1
- package/dist/web/assets/ProjectList-DyiGyT-H.js +0 -1
- package/dist/web/assets/index-EQq56pRa.js +0 -2
|
@@ -21,17 +21,17 @@ const CLAUDE_PROMPT_PATH = NATIVE_PATHS.claude.prompt || path.join(CLAUDE_CONFIG
|
|
|
21
21
|
const CODEX_PROMPT_PATH = path.join(HOME_DIR, '.codex', 'AGENTS.md');
|
|
22
22
|
const GEMINI_PROMPT_PATH = path.join(HOME_DIR, '.gemini', 'GEMINI.md');
|
|
23
23
|
const OPENCODE_PROMPT_PATH = path.join(NATIVE_PATHS.opencode.config, 'AGENTS.md');
|
|
24
|
-
const
|
|
25
|
-
|| path.join(NATIVE_PATHS.
|
|
26
|
-
const MANAGED_OMP_PROMPTS_DIR = path.join(
|
|
24
|
+
const OMP_PROMPTS_DIR = NATIVE_PATHS.omp?.prompts
|
|
25
|
+
|| path.join(NATIVE_PATHS.omp?.dir || path.join(HOME_DIR, '.omp', 'agent'), 'prompts');
|
|
26
|
+
const MANAGED_OMP_PROMPTS_DIR = path.join(OMP_PROMPTS_DIR, 'coding-tool-x');
|
|
27
27
|
|
|
28
|
-
function normalizeApps(apps = {}, defaults = { claude: true, codex: true, gemini: true, opencode: false,
|
|
28
|
+
function normalizeApps(apps = {}, defaults = { claude: true, codex: true, gemini: true, opencode: false, omp: false }) {
|
|
29
29
|
return {
|
|
30
30
|
claude: apps.claude !== undefined ? !!apps.claude : defaults.claude,
|
|
31
31
|
codex: apps.codex !== undefined ? !!apps.codex : defaults.codex,
|
|
32
32
|
gemini: apps.gemini !== undefined ? !!apps.gemini : defaults.gemini,
|
|
33
33
|
opencode: apps.opencode !== undefined ? !!apps.opencode : defaults.opencode,
|
|
34
|
-
|
|
34
|
+
omp: apps.omp !== undefined ? !!apps.omp: defaults.omp
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -216,7 +216,7 @@ function initPromptsData() {
|
|
|
216
216
|
name: '当前使用',
|
|
217
217
|
description: '从现有配置导入',
|
|
218
218
|
content: existingContent,
|
|
219
|
-
apps: normalizeApps({ claude: true, codex: false, gemini: false, opencode: false,
|
|
219
|
+
apps: normalizeApps({ claude: true, codex: false, gemini: false, opencode: false, omp: false }),
|
|
220
220
|
isBuiltin: false,
|
|
221
221
|
isImported: true,
|
|
222
222
|
createdAt: Date.now(),
|
|
@@ -239,7 +239,7 @@ function initPromptsData() {
|
|
|
239
239
|
preset.apps.codex !== normalizedApps.codex ||
|
|
240
240
|
preset.apps.gemini !== normalizedApps.gemini ||
|
|
241
241
|
preset.apps.opencode !== normalizedApps.opencode
|
|
242
|
-
|| preset.apps.
|
|
242
|
+
|| preset.apps.omp !== normalizedApps.omp
|
|
243
243
|
) {
|
|
244
244
|
preset.apps = normalizedApps;
|
|
245
245
|
updated = true;
|
|
@@ -333,7 +333,7 @@ function savePreset(preset) {
|
|
|
333
333
|
writeJsonFile(PROMPTS_FILE, data);
|
|
334
334
|
|
|
335
335
|
if (wasActive) {
|
|
336
|
-
if (existing && normalizeApps(existing.apps).
|
|
336
|
+
if (existing && normalizeApps(existing.apps).omp && !preset.apps.omp) {
|
|
337
337
|
deleteOmpPromptTemplate(existing);
|
|
338
338
|
}
|
|
339
339
|
syncPresetToAllPlatforms(preset);
|
|
@@ -362,7 +362,7 @@ function deletePreset(id) {
|
|
|
362
362
|
data.activePresetId = null;
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
-
if (normalizeApps(preset.apps).
|
|
365
|
+
if (normalizeApps(preset.apps).omp) {
|
|
366
366
|
deleteOmpPromptTemplate(preset);
|
|
367
367
|
}
|
|
368
368
|
|
|
@@ -388,7 +388,7 @@ async function activatePreset(id) {
|
|
|
388
388
|
data.activePresetId = id;
|
|
389
389
|
writeJsonFile(PROMPTS_FILE, data);
|
|
390
390
|
|
|
391
|
-
if (previousPreset && previousPreset.id !== id && normalizeApps(previousPreset.apps).
|
|
391
|
+
if (previousPreset && previousPreset.id !== id && normalizeApps(previousPreset.apps).omp) {
|
|
392
392
|
deleteOmpPromptTemplate(previousPreset);
|
|
393
393
|
}
|
|
394
394
|
|
|
@@ -415,7 +415,7 @@ async function deactivatePrompt() {
|
|
|
415
415
|
codex: deleteFile(CODEX_PROMPT_PATH),
|
|
416
416
|
gemini: deleteFile(GEMINI_PROMPT_PATH),
|
|
417
417
|
opencode: deleteFile(OPENCODE_PROMPT_PATH),
|
|
418
|
-
|
|
418
|
+
omp: activePreset && normalizeApps(activePreset.apps).omp
|
|
419
419
|
? deleteOmpPromptTemplate(activePreset)
|
|
420
420
|
: false
|
|
421
421
|
};
|
|
@@ -456,7 +456,7 @@ function syncPresetToAllPlatforms(preset) {
|
|
|
456
456
|
console.log('[Prompts] Synced to OpenCode:', OPENCODE_PROMPT_PATH);
|
|
457
457
|
}
|
|
458
458
|
|
|
459
|
-
if (apps.
|
|
459
|
+
if (apps.omp) {
|
|
460
460
|
const targetPath = writeOmpPromptTemplate(preset);
|
|
461
461
|
console.log('[Prompts] Synced to OMP:', targetPath);
|
|
462
462
|
}
|
|
@@ -507,7 +507,7 @@ function readPlatformPrompt(platform) {
|
|
|
507
507
|
return readTextFile(GEMINI_PROMPT_PATH, '');
|
|
508
508
|
case 'opencode':
|
|
509
509
|
return readTextFile(OPENCODE_PROMPT_PATH, '');
|
|
510
|
-
case '
|
|
510
|
+
case 'omp':
|
|
511
511
|
throw new Error('OMP 使用 prompts/ 目录中的模板文件,请通过平台状态查看模板列表');
|
|
512
512
|
default:
|
|
513
513
|
throw new Error(`无效的平台: ${platform}`);
|
|
@@ -515,7 +515,7 @@ function readPlatformPrompt(platform) {
|
|
|
515
515
|
}
|
|
516
516
|
|
|
517
517
|
function listOmpPromptTemplates() {
|
|
518
|
-
if (!fs.existsSync(
|
|
518
|
+
if (!fs.existsSync(OMP_PROMPTS_DIR)) {
|
|
519
519
|
return [];
|
|
520
520
|
}
|
|
521
521
|
|
|
@@ -527,7 +527,7 @@ function listOmpPromptTemplates() {
|
|
|
527
527
|
if (entry.isDirectory()) {
|
|
528
528
|
walk(fullPath);
|
|
529
529
|
} else if (entry.isFile() && path.extname(entry.name).toLowerCase() === '.md') {
|
|
530
|
-
const relativePath = path.relative(
|
|
530
|
+
const relativePath = path.relative(OMP_PROMPTS_DIR, fullPath);
|
|
531
531
|
results.push({
|
|
532
532
|
name: path.basename(entry.name, '.md'),
|
|
533
533
|
path: fullPath,
|
|
@@ -539,7 +539,7 @@ function listOmpPromptTemplates() {
|
|
|
539
539
|
};
|
|
540
540
|
|
|
541
541
|
try {
|
|
542
|
-
walk(
|
|
542
|
+
walk(OMP_PROMPTS_DIR);
|
|
543
543
|
} catch (err) {
|
|
544
544
|
console.error(`[Prompts] Failed to list OMP prompt templates:`, err.message);
|
|
545
545
|
}
|
|
@@ -572,10 +572,10 @@ function getPlatformStatus() {
|
|
|
572
572
|
exists: fs.existsSync(OPENCODE_PROMPT_PATH),
|
|
573
573
|
content: readTextFile(OPENCODE_PROMPT_PATH, '')
|
|
574
574
|
},
|
|
575
|
-
|
|
576
|
-
path:
|
|
575
|
+
omp: {
|
|
576
|
+
path: OMP_PROMPTS_DIR,
|
|
577
577
|
managedPath: MANAGED_OMP_PROMPTS_DIR,
|
|
578
|
-
exists: fs.existsSync(
|
|
578
|
+
exists: fs.existsSync(OMP_PROMPTS_DIR),
|
|
579
579
|
templates: listOmpPromptTemplates()
|
|
580
580
|
}
|
|
581
581
|
};
|
|
@@ -599,7 +599,7 @@ function importFromPlatform(platform, presetName) {
|
|
|
599
599
|
name: presetName || `从 ${platform} 导入`,
|
|
600
600
|
description: `从 ${platform} 导入的提示词`,
|
|
601
601
|
content,
|
|
602
|
-
apps: normalizeApps({ claude: false, codex: false, gemini: false, opencode: false,
|
|
602
|
+
apps: normalizeApps({ claude: false, codex: false, gemini: false, opencode: false, omp: false }),
|
|
603
603
|
isBuiltin: false,
|
|
604
604
|
createdAt: Date.now(),
|
|
605
605
|
updatedAt: Date.now()
|
|
@@ -9,7 +9,7 @@ function normalizeToolSource(source = '') {
|
|
|
9
9
|
if (normalized === 'codex') return 'codex';
|
|
10
10
|
if (normalized === 'gemini') return 'gemini';
|
|
11
11
|
if (normalized === 'opencode') return 'opencode';
|
|
12
|
-
if (normalized === '
|
|
12
|
+
if (normalized === 'omp' || normalized === 'omp-agent') return 'omp';
|
|
13
13
|
return 'claude';
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -12,7 +12,7 @@ const PROXY_START_LOG_PATTERNS = {
|
|
|
12
12
|
codex: [/Codex proxy server started on http:\/\/127\.0\.0\.1:\d+/],
|
|
13
13
|
gemini: [/Gemini proxy server started on http:\/\/127\.0\.0\.1:\d+/],
|
|
14
14
|
opencode: [/OpenCode proxy server started on http:\/\/127\.0\.0\.1:\d+/],
|
|
15
|
-
|
|
15
|
+
omp: [
|
|
16
16
|
/OMP models\.yml provider config enabled, port: \d+/,
|
|
17
17
|
/OMP models\.yml 受管 provider 已自动启用,端口: \d+/
|
|
18
18
|
]
|
|
@@ -25,7 +25,7 @@ const {
|
|
|
25
25
|
resolveInsideRoot
|
|
26
26
|
} = require('./config-artifact-paths');
|
|
27
27
|
|
|
28
|
-
const SUPPORTED_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode', '
|
|
28
|
+
const SUPPORTED_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode', 'omp'];
|
|
29
29
|
const SUPPORTED_REPO_PROVIDERS = ['github', 'gitlab', 'local'];
|
|
30
30
|
const DEFAULT_GITHUB_HOST = 'https://github.com';
|
|
31
31
|
const DEFAULT_GITLAB_HOST = 'https://gitlab.com';
|
|
@@ -174,7 +174,7 @@ const DEFAULT_REPOS_BY_PLATFORM = {
|
|
|
174
174
|
codex: [],
|
|
175
175
|
gemini: [],
|
|
176
176
|
opencode: [],
|
|
177
|
-
|
|
177
|
+
omp: []
|
|
178
178
|
};
|
|
179
179
|
|
|
180
180
|
const CLAUDE_SKILLS_DIR = NATIVE_PATHS.claude.skills
|
|
@@ -205,11 +205,11 @@ const PLATFORM_CONFIG = {
|
|
|
205
205
|
reposFile: PATHS.skillRepos.opencode,
|
|
206
206
|
cacheFile: PATHS.skillCaches.opencode
|
|
207
207
|
},
|
|
208
|
-
|
|
209
|
-
installDir: NATIVE_PATHS.
|
|
210
|
-
storageDir: PATHS.localSkills.
|
|
211
|
-
reposFile: PATHS.skillRepos.
|
|
212
|
-
cacheFile: PATHS.skillCaches.
|
|
208
|
+
omp: {
|
|
209
|
+
installDir: NATIVE_PATHS.omp.skills,
|
|
210
|
+
storageDir: PATHS.localSkills.omp,
|
|
211
|
+
reposFile: PATHS.skillRepos.omp,
|
|
212
|
+
cacheFile: PATHS.skillCaches.omp
|
|
213
213
|
}
|
|
214
214
|
};
|
|
215
215
|
|
|
@@ -13,7 +13,7 @@ const { getEffectiveApiKey: getClaudeEffectiveApiKey } = require('./channels');
|
|
|
13
13
|
const { getEffectiveApiKey: getCodexEffectiveApiKey } = require('./codex-channels');
|
|
14
14
|
const { getEffectiveApiKey: getGeminiEffectiveApiKey } = require('./gemini-channels');
|
|
15
15
|
const { getEffectiveApiKey: getOpenCodeEffectiveApiKey } = require('./opencode-channels');
|
|
16
|
-
const { getEffectiveApiKey:
|
|
16
|
+
const { getEffectiveApiKey: getOmpEffectiveApiKey } = require('./omp-channels');
|
|
17
17
|
const { loadClaudeRequestTemplate } = require('./request-logger');
|
|
18
18
|
|
|
19
19
|
// 测试结果缓存
|
|
@@ -103,8 +103,8 @@ function resolveExplicitModel(channel, model) {
|
|
|
103
103
|
|
|
104
104
|
function resolveEffectiveApiKey(channel, channelType) {
|
|
105
105
|
switch (channelType) {
|
|
106
|
-
case '
|
|
107
|
-
return
|
|
106
|
+
case 'omp':
|
|
107
|
+
return getOmpEffectiveApiKey(channel);
|
|
108
108
|
case 'codex':
|
|
109
109
|
return getCodexEffectiveApiKey(channel);
|
|
110
110
|
case 'gemini':
|
|
@@ -381,7 +381,7 @@ function extractJsonPayloads(responseData) {
|
|
|
381
381
|
* @param {number} timeout - 超时时间(毫秒)
|
|
382
382
|
* @param {string} channelType - 请求格式类型:'claude' | 'codex' | 'gemini' | 'opencode'
|
|
383
383
|
* @param {Object} options - 可选行为
|
|
384
|
-
* @param {string} options.authSourceType - API key 来源平台;OMP 使用 '
|
|
384
|
+
* @param {string} options.authSourceType - API key 来源平台;OMP 使用 'omp',请求格式仍由 channelType 决定
|
|
385
385
|
* @returns {Promise<Object>} 测试结果
|
|
386
386
|
*/
|
|
387
387
|
async function testChannelSpeed(channel, timeout = DEFAULT_TIMEOUT, channelType = 'claude', options = {}) {
|
|
@@ -439,7 +439,7 @@ async function testChannelSpeed(channel, timeout = DEFAULT_TIMEOUT, channelType
|
|
|
439
439
|
|
|
440
440
|
// 直接测试 API 功能(发送测试消息)
|
|
441
441
|
// 不再单独测试网络连通性,因为直接 GET base_url 可能返回 404
|
|
442
|
-
const
|
|
442
|
+
const aompResult = await testAPIFunctionality(
|
|
443
443
|
testUrl,
|
|
444
444
|
effectiveApiKey,
|
|
445
445
|
sanitizedTimeout,
|
|
@@ -448,8 +448,8 @@ async function testChannelSpeed(channel, timeout = DEFAULT_TIMEOUT, channelType
|
|
|
448
448
|
channel
|
|
449
449
|
);
|
|
450
450
|
|
|
451
|
-
const success =
|
|
452
|
-
const networkOk =
|
|
451
|
+
const success = aompResult.success;
|
|
452
|
+
const networkOk = aompResult.latency !== null; // 如果有延迟数据,说明网络是通的
|
|
453
453
|
|
|
454
454
|
// 缓存结果
|
|
455
455
|
const finalResult = {
|
|
@@ -458,13 +458,13 @@ async function testChannelSpeed(channel, timeout = DEFAULT_TIMEOUT, channelType
|
|
|
458
458
|
success,
|
|
459
459
|
networkOk,
|
|
460
460
|
apiOk: success,
|
|
461
|
-
statusCode:
|
|
462
|
-
error: success ? null : (
|
|
463
|
-
latency:
|
|
461
|
+
statusCode: aompResult.statusCode || null,
|
|
462
|
+
error: success ? null : (aompResult.error || '测试失败'),
|
|
463
|
+
latency: aompResult.latency ?? null, // 无论成功失败都保留延迟数据(保留 0ms)
|
|
464
464
|
testedAt: Date.now(),
|
|
465
|
-
testedModel:
|
|
466
|
-
availableModels:
|
|
467
|
-
modelDetectionMethod:
|
|
465
|
+
testedModel: aompResult.testedModel,
|
|
466
|
+
availableModels: aompResult.availableModels,
|
|
467
|
+
modelDetectionMethod: aompResult.modelDetectionMethod
|
|
468
468
|
};
|
|
469
469
|
|
|
470
470
|
testResultsCache.set(channel.id, finalResult);
|
|
@@ -661,11 +661,11 @@ async function testAPIFunctionality(baseUrl, apiKey, timeout, channelType = 'cla
|
|
|
661
661
|
|
|
662
662
|
if (channelType === 'claude') {
|
|
663
663
|
// Anthropic Messages API - 模拟 Claude Code 请求格式
|
|
664
|
-
let
|
|
665
|
-
if (!
|
|
666
|
-
|
|
664
|
+
let aompPath = parsedUrl.pathname.replace(/\/$/, '');
|
|
665
|
+
if (!aompPath.endsWith('/messages')) {
|
|
666
|
+
aompPath = aompPath + (aompPath.endsWith('/v1') ? '/messages' : '/v1/messages');
|
|
667
667
|
}
|
|
668
|
-
|
|
668
|
+
aompPath += '?beta=true';
|
|
669
669
|
|
|
670
670
|
testModel = modelProbe?.preferredTestModel || normalizeNonEmptyString(model) || 'claude-sonnet-4-20250514';
|
|
671
671
|
const sessionId = typeof crypto.randomUUID === 'function'
|
|
@@ -686,20 +686,20 @@ async function testAPIFunctionality(baseUrl, apiKey, timeout, channelType = 'cla
|
|
|
686
686
|
tools: toolsToUse
|
|
687
687
|
};
|
|
688
688
|
primaryRequestConfig = {
|
|
689
|
-
|
|
689
|
+
aompPath,
|
|
690
690
|
requestBody: JSON.stringify(requestPayload),
|
|
691
691
|
headers: buildClaudeRequestHeaders(apiKey, { hasTools: true }),
|
|
692
692
|
isStreamingResponse: true
|
|
693
693
|
};
|
|
694
694
|
// Fallback: non-streaming for gateways that don't support SSE
|
|
695
695
|
fallbackRequestConfig = {
|
|
696
|
-
|
|
696
|
+
aompPath,
|
|
697
697
|
requestBody: JSON.stringify({ ...requestPayload, stream: false }),
|
|
698
698
|
headers: buildClaudeRequestHeaders(apiKey, { hasTools: true }),
|
|
699
699
|
isStreamingResponse: false
|
|
700
700
|
};
|
|
701
701
|
} else if (channelType === 'codex') {
|
|
702
|
-
const
|
|
702
|
+
const aompPath = buildCodexResponsesPath(parsedUrl);
|
|
703
703
|
testModel = modelProbe?.preferredTestModel || normalizeNonEmptyString(model) || 'gpt-5-codex';
|
|
704
704
|
const codexSessionId = `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;
|
|
705
705
|
|
|
@@ -712,7 +712,7 @@ async function testAPIFunctionality(baseUrl, apiKey, timeout, channelType = 'cla
|
|
|
712
712
|
};
|
|
713
713
|
|
|
714
714
|
primaryRequestConfig = {
|
|
715
|
-
|
|
715
|
+
aompPath,
|
|
716
716
|
requestBody: JSON.stringify({ ...baseBody, stream: false }),
|
|
717
717
|
headers: {
|
|
718
718
|
'Authorization': `Bearer ${apiKey || ''}`,
|
|
@@ -729,7 +729,7 @@ async function testAPIFunctionality(baseUrl, apiKey, timeout, channelType = 'cla
|
|
|
729
729
|
};
|
|
730
730
|
|
|
731
731
|
fallbackRequestConfig = {
|
|
732
|
-
|
|
732
|
+
aompPath,
|
|
733
733
|
requestBody: JSON.stringify({ ...baseBody, stream: true }),
|
|
734
734
|
headers: {
|
|
735
735
|
...primaryRequestConfig.headers,
|
|
@@ -742,7 +742,7 @@ async function testAPIFunctionality(baseUrl, apiKey, timeout, channelType = 'cla
|
|
|
742
742
|
const useCliFormat = shouldUseGeminiCliFormat(parsedUrl);
|
|
743
743
|
|
|
744
744
|
const cliRequestConfig = {
|
|
745
|
-
|
|
745
|
+
aompPath: buildGeminiCliGeneratePath(parsedUrl),
|
|
746
746
|
requestBody: JSON.stringify({
|
|
747
747
|
project: '',
|
|
748
748
|
model: testModel,
|
|
@@ -764,7 +764,7 @@ async function testAPIFunctionality(baseUrl, apiKey, timeout, channelType = 'cla
|
|
|
764
764
|
};
|
|
765
765
|
|
|
766
766
|
const nativeRequestConfig = {
|
|
767
|
-
|
|
767
|
+
aompPath: buildGeminiNativeGeneratePath(parsedUrl, testModel),
|
|
768
768
|
requestBody: JSON.stringify({
|
|
769
769
|
contents: [{ role: 'user', parts: [{ text: 'ping' }] }],
|
|
770
770
|
generationConfig: { maxOutputTokens: 1, temperature: 0 }
|
|
@@ -783,12 +783,12 @@ async function testAPIFunctionality(baseUrl, apiKey, timeout, channelType = 'cla
|
|
|
783
783
|
fallbackRequestConfig = useCliFormat ? nativeRequestConfig : cliRequestConfig;
|
|
784
784
|
} else {
|
|
785
785
|
testModel = modelProbe?.preferredTestModel || normalizeNonEmptyString(model) || 'gpt-4o-mini';
|
|
786
|
-
let
|
|
787
|
-
if (!
|
|
788
|
-
|
|
786
|
+
let aompPath = parsedUrl.pathname.replace(/\/$/, '');
|
|
787
|
+
if (!aompPath.endsWith('/chat/completions')) {
|
|
788
|
+
aompPath = aompPath + (aompPath.endsWith('/v1') ? '/chat/completions' : '/v1/chat/completions');
|
|
789
789
|
}
|
|
790
790
|
primaryRequestConfig = {
|
|
791
|
-
|
|
791
|
+
aompPath,
|
|
792
792
|
requestBody: JSON.stringify({
|
|
793
793
|
model: testModel,
|
|
794
794
|
max_tokens: 1,
|
|
@@ -808,7 +808,7 @@ async function testAPIFunctionality(baseUrl, apiKey, timeout, channelType = 'cla
|
|
|
808
808
|
const options = {
|
|
809
809
|
hostname: parsedUrl.hostname,
|
|
810
810
|
port: parsedUrl.port || (isHttps ? 443 : 80),
|
|
811
|
-
path: requestConfig.
|
|
811
|
+
path: requestConfig.aompPath,
|
|
812
812
|
method: 'POST',
|
|
813
813
|
timeout,
|
|
814
814
|
headers: requestConfig.headers
|
|
@@ -24,21 +24,21 @@ const DEFAULT_UI_CONFIG = {
|
|
|
24
24
|
codex: false,
|
|
25
25
|
gemini: false,
|
|
26
26
|
opencode: false,
|
|
27
|
-
|
|
27
|
+
omp: false
|
|
28
28
|
},
|
|
29
29
|
channelCollapse: {
|
|
30
30
|
claude: [],
|
|
31
31
|
codex: [],
|
|
32
32
|
gemini: [],
|
|
33
33
|
opencode: [],
|
|
34
|
-
|
|
34
|
+
omp: []
|
|
35
35
|
},
|
|
36
36
|
channelOrder: {
|
|
37
37
|
claude: [],
|
|
38
38
|
codex: [],
|
|
39
39
|
gemini: [],
|
|
40
40
|
opencode: [],
|
|
41
|
-
|
|
41
|
+
omp: []
|
|
42
42
|
},
|
|
43
43
|
dashboardChannelOrder: DEFAULT_HOME_CLI_COLUMNS,
|
|
44
44
|
homeCliColumns: DEFAULT_HOME_CLI_COLUMNS,
|
|
@@ -630,7 +630,7 @@ async function getAllAvailableProjects() {
|
|
|
630
630
|
const codexSessionsService = require('./codex-sessions');
|
|
631
631
|
const geminiSessionsService = require('./gemini-sessions');
|
|
632
632
|
const opencodeSessionsService = require('./opencode-sessions');
|
|
633
|
-
const
|
|
633
|
+
const ompSessionsService = require('./omp-sessions');
|
|
634
634
|
const { isCodexInstalled } = require('./codex-config');
|
|
635
635
|
const { isGeminiInstalled } = require('./gemini-config');
|
|
636
636
|
const { isOpenCodeInstalled } = require('./opencode-sessions');
|
|
@@ -704,10 +704,10 @@ async function getAllAvailableProjects() {
|
|
|
704
704
|
}
|
|
705
705
|
|
|
706
706
|
try {
|
|
707
|
-
const
|
|
708
|
-
const list = Array.isArray(
|
|
709
|
-
if (list.length > 0 ||
|
|
710
|
-
list.forEach(project => addProject('
|
|
707
|
+
const ompProjects = ompSessionsService.getProjects();
|
|
708
|
+
const list = Array.isArray(ompProjects) ? ompProjects : [];
|
|
709
|
+
if (list.length > 0 || ompSessionsService.isOmpInstalled()) {
|
|
710
|
+
list.forEach(project => addProject('omp', project));
|
|
711
711
|
}
|
|
712
712
|
} catch (error) {
|
|
713
713
|
console.error('获取 OMP 项目失败:', error.message);
|
|
@@ -722,7 +722,7 @@ async function getAllAvailableProjects() {
|
|
|
722
722
|
/**
|
|
723
723
|
* 在工作区中启动 CLI 工具
|
|
724
724
|
* @param {string} workspaceId 工作区 ID
|
|
725
|
-
* @param {string} tool 工具名称 (claude/codex/gemini/opencode/
|
|
725
|
+
* @param {string} tool 工具名称 (claude/codex/gemini/opencode/omp/omp)
|
|
726
726
|
* @param {string} projectName 可选,工作区内的项目名
|
|
727
727
|
* @returns {object} 启动信息
|
|
728
728
|
*/
|
|
@@ -749,7 +749,7 @@ function getLaunchCommand(workspaceId, tool, projectName = null) {
|
|
|
749
749
|
}
|
|
750
750
|
}
|
|
751
751
|
|
|
752
|
-
const normalizedTool = tool === 'omp' ? '
|
|
752
|
+
const normalizedTool = tool === 'omp' ? 'omp' : tool;
|
|
753
753
|
|
|
754
754
|
// 根据工具类型生成启动命令
|
|
755
755
|
const commands = {
|
|
@@ -757,7 +757,7 @@ function getLaunchCommand(workspaceId, tool, projectName = null) {
|
|
|
757
757
|
codex: 'codex',
|
|
758
758
|
gemini: 'gemini',
|
|
759
759
|
opencode: 'opencode',
|
|
760
|
-
|
|
760
|
+
omp: 'omp'
|
|
761
761
|
};
|
|
762
762
|
|
|
763
763
|
const cmd = commands[normalizedTool];
|
|
@@ -183,13 +183,13 @@ function inferSource(log) {
|
|
|
183
183
|
if (log.toolType.includes('codex')) return 'codex';
|
|
184
184
|
if (log.toolType.includes('gemini')) return 'gemini';
|
|
185
185
|
if (log.toolType.includes('opencode')) return 'opencode';
|
|
186
|
-
if (log.toolType.includes('
|
|
186
|
+
if (log.toolType.includes('omp')) return 'omp';
|
|
187
187
|
}
|
|
188
188
|
if (typeof log.model === 'string') {
|
|
189
189
|
const model = log.model.toLowerCase();
|
|
190
190
|
if (model.includes('gemini')) return 'gemini';
|
|
191
191
|
if (model.includes('opencode')) return 'opencode';
|
|
192
|
-
if (model.includes('
|
|
192
|
+
if (model.includes('omp')) return 'omp';
|
|
193
193
|
if (model.includes('gpt') || model.includes('o1') || model.includes('o3')) return 'codex';
|
|
194
194
|
if (model.includes('claude')) return 'claude';
|
|
195
195
|
}
|
|
@@ -197,9 +197,9 @@ function inferSource(log) {
|
|
|
197
197
|
if (log.action.includes('codex')) return 'codex';
|
|
198
198
|
if (log.action.includes('gemini')) return 'gemini';
|
|
199
199
|
if (log.action.includes('opencode')) return 'opencode';
|
|
200
|
-
if (log.action.includes('
|
|
200
|
+
if (log.action.includes('omp')) return 'omp';
|
|
201
201
|
}
|
|
202
|
-
if (log.channelType === 'codex' || log.channelType === 'gemini' || log.channelType === 'opencode' || log.channelType === '
|
|
202
|
+
if (log.channelType === 'codex' || log.channelType === 'gemini' || log.channelType === 'opencode' || log.channelType === 'omp') {
|
|
203
203
|
return log.channelType;
|
|
204
204
|
}
|
|
205
205
|
return 'claude';
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
const BUILT_IN_CLI_PLATFORMS = [
|
|
2
|
+
{
|
|
3
|
+
key: 'claude',
|
|
4
|
+
title: 'ClaudeCode',
|
|
5
|
+
label: 'Claude Code',
|
|
6
|
+
command: 'claude',
|
|
7
|
+
color: '#18a058',
|
|
8
|
+
defaultVisible: true,
|
|
9
|
+
supportsManagedChannels: true,
|
|
10
|
+
supportsManagedConfig: true,
|
|
11
|
+
supportsProxy: true,
|
|
12
|
+
supportsProjects: true,
|
|
13
|
+
supportsSessions: true,
|
|
14
|
+
supportsSkills: true,
|
|
15
|
+
supportsCommands: true,
|
|
16
|
+
supportsPlugins: true,
|
|
17
|
+
supportsAgents: true
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
key: 'codex',
|
|
21
|
+
title: 'Codex-CLI',
|
|
22
|
+
label: 'Codex',
|
|
23
|
+
command: 'codex',
|
|
24
|
+
color: '#3b82f6',
|
|
25
|
+
defaultVisible: true,
|
|
26
|
+
supportsManagedChannels: true,
|
|
27
|
+
supportsManagedConfig: true,
|
|
28
|
+
supportsProxy: true,
|
|
29
|
+
supportsProjects: true,
|
|
30
|
+
supportsSessions: true,
|
|
31
|
+
supportsSkills: true,
|
|
32
|
+
supportsCommands: true,
|
|
33
|
+
supportsPlugins: true,
|
|
34
|
+
supportsAgents: true
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
key: 'gemini',
|
|
38
|
+
title: 'Gemini-CLI',
|
|
39
|
+
label: 'Gemini',
|
|
40
|
+
command: 'gemini',
|
|
41
|
+
color: '#a855f7',
|
|
42
|
+
defaultVisible: true,
|
|
43
|
+
supportsManagedChannels: true,
|
|
44
|
+
supportsManagedConfig: true,
|
|
45
|
+
supportsProxy: true,
|
|
46
|
+
supportsProjects: true,
|
|
47
|
+
supportsSessions: true,
|
|
48
|
+
supportsSkills: true,
|
|
49
|
+
supportsCommands: true,
|
|
50
|
+
supportsPlugins: false,
|
|
51
|
+
supportsAgents: true
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
key: 'opencode',
|
|
55
|
+
title: 'OpenCode',
|
|
56
|
+
label: 'OpenCode',
|
|
57
|
+
command: 'opencode',
|
|
58
|
+
color: '#ea580c',
|
|
59
|
+
defaultVisible: true,
|
|
60
|
+
supportsManagedChannels: true,
|
|
61
|
+
supportsManagedConfig: true,
|
|
62
|
+
supportsProxy: true,
|
|
63
|
+
supportsProjects: true,
|
|
64
|
+
supportsSessions: true,
|
|
65
|
+
supportsSkills: true,
|
|
66
|
+
supportsCommands: true,
|
|
67
|
+
supportsPlugins: true,
|
|
68
|
+
supportsAgents: true
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
key: 'omp',
|
|
72
|
+
title: 'OMP',
|
|
73
|
+
label: 'OMP',
|
|
74
|
+
command: 'omp',
|
|
75
|
+
color: '#0f9f9a',
|
|
76
|
+
defaultVisible: false,
|
|
77
|
+
supportsManagedChannels: true,
|
|
78
|
+
supportsManagedConfig: true,
|
|
79
|
+
supportsProxy: true,
|
|
80
|
+
supportsProjects: true,
|
|
81
|
+
supportsSessions: true,
|
|
82
|
+
supportsSkills: true,
|
|
83
|
+
supportsCommands: true,
|
|
84
|
+
supportsPlugins: true,
|
|
85
|
+
supportsAgents: false
|
|
86
|
+
}
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
const DEFAULT_HOME_CLI_COLUMNS = ['claude', 'codex', 'gemini', 'opencode'];
|
|
90
|
+
const MAX_HOME_CLI_COLUMNS = 4;
|
|
91
|
+
function normalizePlatformKey(value = '') {
|
|
92
|
+
return String(value || '').trim().toLowerCase();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function getBuiltInPlatformKeys() {
|
|
96
|
+
return BUILT_IN_CLI_PLATFORMS.map(platform => platform.key);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function getPlatformDefinition(key) {
|
|
100
|
+
const normalizedKey = normalizePlatformKey(key);
|
|
101
|
+
return BUILT_IN_CLI_PLATFORMS.find(platform => platform.key === normalizedKey) || null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function normalizeCustomCliPlatform(input = {}) {
|
|
105
|
+
const rawKey = normalizePlatformKey(input.key);
|
|
106
|
+
const key = rawKey
|
|
107
|
+
.replace(/[^a-z0-9_-]/g, '-')
|
|
108
|
+
.replace(/-+/g, '-')
|
|
109
|
+
.replace(/^-|-$/g, '');
|
|
110
|
+
|
|
111
|
+
if (!key || getPlatformDefinition(key)) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const name = String(input.name || input.title || key).trim() || key;
|
|
116
|
+
const command = String(input.command || key).trim() || key;
|
|
117
|
+
return {
|
|
118
|
+
key,
|
|
119
|
+
name,
|
|
120
|
+
title: String(input.title || name).trim() || name,
|
|
121
|
+
command,
|
|
122
|
+
configDir: String(input.configDir || '').trim(),
|
|
123
|
+
icon: String(input.icon || '').trim(),
|
|
124
|
+
color: String(input.color || '').trim(),
|
|
125
|
+
enabled: input.enabled !== false,
|
|
126
|
+
custom: true,
|
|
127
|
+
supportsManagedChannels: false,
|
|
128
|
+
supportsManagedConfig: false,
|
|
129
|
+
supportsProxy: false,
|
|
130
|
+
supportsProjects: false,
|
|
131
|
+
supportsSessions: false,
|
|
132
|
+
supportsSkills: false,
|
|
133
|
+
supportsCommands: false,
|
|
134
|
+
supportsPlugins: false,
|
|
135
|
+
supportsAgents: false
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function normalizeCustomCliPlatforms(input = []) {
|
|
140
|
+
const result = [];
|
|
141
|
+
const seen = new Set();
|
|
142
|
+
|
|
143
|
+
if (!Array.isArray(input)) {
|
|
144
|
+
return result;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
input.forEach((item) => {
|
|
148
|
+
const normalized = normalizeCustomCliPlatform(item);
|
|
149
|
+
if (!normalized || seen.has(normalized.key)) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
seen.add(normalized.key);
|
|
153
|
+
result.push(normalized);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function normalizeHomeCliColumns(input = [], customCliPlatforms = []) {
|
|
160
|
+
const customKeys = new Set(
|
|
161
|
+
normalizeCustomCliPlatforms(customCliPlatforms)
|
|
162
|
+
.filter(platform => platform.enabled !== false)
|
|
163
|
+
.map(platform => platform.key)
|
|
164
|
+
);
|
|
165
|
+
const builtInKeys = new Set(getBuiltInPlatformKeys());
|
|
166
|
+
const allowed = key => builtInKeys.has(key) || customKeys.has(key);
|
|
167
|
+
const result = [];
|
|
168
|
+
|
|
169
|
+
if (Array.isArray(input)) {
|
|
170
|
+
input.forEach((value) => {
|
|
171
|
+
const key = normalizePlatformKey(value);
|
|
172
|
+
if (!key || result.includes(key) || !allowed(key)) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
result.push(key);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
DEFAULT_HOME_CLI_COLUMNS.forEach((key) => {
|
|
180
|
+
if (result.length >= MAX_HOME_CLI_COLUMNS) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (!result.includes(key)) {
|
|
184
|
+
result.push(key);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
return result.slice(0, MAX_HOME_CLI_COLUMNS);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
module.exports = {
|
|
192
|
+
BUILT_IN_CLI_PLATFORMS,
|
|
193
|
+
DEFAULT_HOME_CLI_COLUMNS,
|
|
194
|
+
MAX_HOME_CLI_COLUMNS,
|
|
195
|
+
getBuiltInPlatformKeys,
|
|
196
|
+
getPlatformDefinition,
|
|
197
|
+
normalizePlatformKey,
|
|
198
|
+
normalizeCustomCliPlatform,
|
|
199
|
+
normalizeCustomCliPlatforms,
|
|
200
|
+
normalizeHomeCliColumns
|
|
201
|
+
};
|