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.
Files changed (72) hide show
  1. package/README.md +5 -6
  2. package/dist/web/assets/{Analytics-Dma_j2Rq.js → Analytics-Dpje9L84.js} +1 -1
  3. package/dist/web/assets/{ConfigTemplates-C49Y1PLH.js → ConfigTemplates-Cz6kasek.js} +1 -1
  4. package/dist/web/assets/Home-BwTaYu3q.js +1 -0
  5. package/dist/web/assets/Home-Jom_ZcdY.css +1 -0
  6. package/dist/web/assets/{PluginManager-B1ECTHyY.js → PluginManager-DsN-xNXx.js} +1 -1
  7. package/dist/web/assets/ProjectList-4BCObimU.js +1 -0
  8. package/dist/web/assets/{ProjectList-B_L55-l9.css → ProjectList-D3a0oRum.css} +1 -1
  9. package/dist/web/assets/{SessionList-CH5GwwiJ.js → SessionList-D4c8FRzq.js} +1 -1
  10. package/dist/web/assets/{SkillManager-CRyVhjYQ.js → SkillManager-C-KYbXB5.js} +1 -1
  11. package/dist/web/assets/{WorkspaceManager-CO9tclVt.js → WorkspaceManager-B-BlPJHX.js} +1 -1
  12. package/dist/web/assets/index-Btfvh0GG.js +2 -0
  13. package/dist/web/assets/{index-CM26UrnJ.css → index-CLNa6DhH.css} +1 -1
  14. package/dist/web/index.html +2 -2
  15. package/package.json +2 -1
  16. package/src/commands/channels.js +8 -8
  17. package/src/commands/daemon.js +4 -4
  18. package/src/commands/doctor.js +1 -1
  19. package/src/commands/logs.js +1 -3
  20. package/src/commands/port-config.js +4 -4
  21. package/src/commands/proxy-control.js +13 -13
  22. package/src/commands/stats.js +6 -6
  23. package/src/commands/toggle-proxy.js +8 -8
  24. package/src/config/default.js +3 -3
  25. package/src/config/paths.js +46 -49
  26. package/src/index.js +4 -5
  27. package/src/server/api/commands.js +1 -1
  28. package/src/server/api/config-export.js +2 -2
  29. package/src/server/api/config-registry.js +1 -1
  30. package/src/server/api/config.js +1 -1
  31. package/src/server/api/dashboard.js +16 -16
  32. package/src/server/api/mcp.js +2 -2
  33. package/src/server/api/{pi-channels.js → omp-channels.js} +15 -15
  34. package/src/server/api/{pi-config.js → omp-config.js} +13 -13
  35. package/src/server/api/{pi-projects.js → omp-projects.js} +5 -5
  36. package/src/server/api/{pi-proxy.js → omp-proxy.js} +18 -18
  37. package/src/server/api/{pi-sessions.js → omp-sessions.js} +21 -21
  38. package/src/server/api/{pi-statistics.js → omp-statistics.js} +1 -1
  39. package/src/server/api/plugins.js +1 -1
  40. package/src/server/api/skills.js +1 -1
  41. package/src/server/api/workspaces.js +1 -1
  42. package/src/server/index.js +10 -10
  43. package/src/server/{pi-proxy-server.js → omp-proxy-server.js} +13 -13
  44. package/src/server/services/channel-balance.js +3 -3
  45. package/src/server/services/channel-scheduler.js +4 -4
  46. package/src/server/services/commands-service.js +5 -5
  47. package/src/server/services/config-export-service.js +53 -53
  48. package/src/server/services/config-registry-service.js +8 -8
  49. package/src/server/services/config-sync-manager.js +26 -26
  50. package/src/server/services/config-templates-service.js +28 -28
  51. package/src/server/services/mcp-service.js +20 -20
  52. package/src/server/services/notification-hooks.js +138 -6
  53. package/src/server/services/{pi-auth-providers.js → omp-auth-providers.js} +2 -2
  54. package/src/server/services/{pi-channels.js → omp-channels.js} +5 -5
  55. package/src/server/services/{pi-config.js → omp-config.js} +47 -65
  56. package/src/server/services/{pi-sessions.js → omp-sessions.js} +20 -20
  57. package/src/server/services/{pi-settings-manager.js → omp-settings-manager.js} +422 -18
  58. package/src/server/services/{pi-statistics-service.js → omp-statistics-service.js} +2 -2
  59. package/src/server/services/plugins-service.js +122 -122
  60. package/src/server/services/prompts-service.js +20 -20
  61. package/src/server/services/proxy-log-helper.js +1 -1
  62. package/src/server/services/proxy-runtime.js +1 -1
  63. package/src/server/services/skill-service.js +7 -7
  64. package/src/server/services/speed-test.js +29 -29
  65. package/src/server/services/ui-config.js +3 -3
  66. package/src/server/services/workspace-service.js +8 -8
  67. package/src/server/websocket-server.js +4 -4
  68. package/src/shared/platforms.js +201 -0
  69. package/dist/web/assets/Home-DGGC8H4g.js +0 -1
  70. package/dist/web/assets/Home-ewgeIhF7.css +0 -1
  71. package/dist/web/assets/ProjectList-DyiGyT-H.js +0 -1
  72. 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 PI_PROMPTS_DIR = NATIVE_PATHS.pi?.prompts
25
- || path.join(NATIVE_PATHS.pi?.dir || path.join(HOME_DIR, '.omp', 'agent'), 'prompts');
26
- const MANAGED_OMP_PROMPTS_DIR = path.join(PI_PROMPTS_DIR, 'coding-tool-x');
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, pi: 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
- pi: apps.pi !== undefined ? !!apps.pi : defaults.pi
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, pi: 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.pi !== normalizedApps.pi
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).pi && !preset.apps.pi) {
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).pi) {
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).pi) {
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
- pi: activePreset && normalizeApps(activePreset.apps).pi
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.pi) {
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 'pi':
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(PI_PROMPTS_DIR)) {
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(PI_PROMPTS_DIR, fullPath);
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(PI_PROMPTS_DIR);
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
- pi: {
576
- path: PI_PROMPTS_DIR,
575
+ omp: {
576
+ path: OMP_PROMPTS_DIR,
577
577
  managedPath: MANAGED_OMP_PROMPTS_DIR,
578
- exists: fs.existsSync(PI_PROMPTS_DIR),
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, pi: 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 === 'pi' || normalized === 'pi-agent') return 'pi';
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
- pi: [
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', 'pi'];
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
- pi: []
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
- pi: {
209
- installDir: NATIVE_PATHS.pi.skills,
210
- storageDir: PATHS.localSkills.pi,
211
- reposFile: PATHS.skillRepos.pi,
212
- cacheFile: PATHS.skillCaches.pi
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: getPiEffectiveApiKey } = require('./pi-channels');
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 'pi':
107
- return getPiEffectiveApiKey(channel);
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 使用 'pi',请求格式仍由 channelType 决定
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 apiResult = await testAPIFunctionality(
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 = apiResult.success;
452
- const networkOk = apiResult.latency !== null; // 如果有延迟数据,说明网络是通的
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: apiResult.statusCode || null,
462
- error: success ? null : (apiResult.error || '测试失败'),
463
- latency: apiResult.latency ?? null, // 无论成功失败都保留延迟数据(保留 0ms)
461
+ statusCode: aompResult.statusCode || null,
462
+ error: success ? null : (aompResult.error || '测试失败'),
463
+ latency: aompResult.latency ?? null, // 无论成功失败都保留延迟数据(保留 0ms)
464
464
  testedAt: Date.now(),
465
- testedModel: apiResult.testedModel,
466
- availableModels: apiResult.availableModels,
467
- modelDetectionMethod: apiResult.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 apiPath = parsedUrl.pathname.replace(/\/$/, '');
665
- if (!apiPath.endsWith('/messages')) {
666
- apiPath = apiPath + (apiPath.endsWith('/v1') ? '/messages' : '/v1/messages');
664
+ let aompPath = parsedUrl.pathname.replace(/\/$/, '');
665
+ if (!aompPath.endsWith('/messages')) {
666
+ aompPath = aompPath + (aompPath.endsWith('/v1') ? '/messages' : '/v1/messages');
667
667
  }
668
- apiPath += '?beta=true';
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
- apiPath,
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
- apiPath,
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 apiPath = buildCodexResponsesPath(parsedUrl);
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
- apiPath,
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
- apiPath,
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
- apiPath: buildGeminiCliGeneratePath(parsedUrl),
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
- apiPath: buildGeminiNativeGeneratePath(parsedUrl, testModel),
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 apiPath = parsedUrl.pathname.replace(/\/$/, '');
787
- if (!apiPath.endsWith('/chat/completions')) {
788
- apiPath = apiPath + (apiPath.endsWith('/v1') ? '/chat/completions' : '/v1/chat/completions');
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
- apiPath,
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.apiPath,
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
- pi: false
27
+ omp: false
28
28
  },
29
29
  channelCollapse: {
30
30
  claude: [],
31
31
  codex: [],
32
32
  gemini: [],
33
33
  opencode: [],
34
- pi: []
34
+ omp: []
35
35
  },
36
36
  channelOrder: {
37
37
  claude: [],
38
38
  codex: [],
39
39
  gemini: [],
40
40
  opencode: [],
41
- pi: []
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 piSessionsService = require('./pi-sessions');
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 piProjects = piSessionsService.getProjects();
708
- const list = Array.isArray(piProjects) ? piProjects : [];
709
- if (list.length > 0 || piSessionsService.isPiInstalled()) {
710
- list.forEach(project => addProject('pi', project));
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/pi/omp)
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' ? 'pi' : tool;
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
- pi: 'omp'
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('pi')) return 'pi';
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('pi')) return 'pi';
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('pi')) return 'pi';
200
+ if (log.action.includes('omp')) return 'omp';
201
201
  }
202
- if (log.channelType === 'codex' || log.channelType === 'gemini' || log.channelType === 'opencode' || log.channelType === 'pi') {
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
+ };