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
|
@@ -19,7 +19,7 @@ const HOME_DIR = resolvePreferredHomeDir(process.platform, process.env, os.homed
|
|
|
19
19
|
const MCP_SERVERS_FILE = PATHS.mcpServers;
|
|
20
20
|
|
|
21
21
|
// 各平台配置文件路径
|
|
22
|
-
const CLAUDE_CONFIG_PATH = path.join(HOME_DIR, '.claude.json');
|
|
22
|
+
const CLAUDE_CONFIG_PATH = NATIVE_PATHS.claude.mcp || path.join(HOME_DIR, '.claude.json');
|
|
23
23
|
const CODEX_CONFIG_PATH = NATIVE_PATHS.codex.config;
|
|
24
24
|
const GEMINI_CONFIG_PATH = path.join(path.dirname(NATIVE_PATHS.gemini.env), 'settings.json');
|
|
25
25
|
const OPENCODE_CONFIG_DIR = NATIVE_PATHS.opencode.config;
|
|
@@ -28,6 +28,8 @@ const OPENCODE_CONFIG_PATHS = {
|
|
|
28
28
|
json: path.join(OPENCODE_CONFIG_DIR, 'opencode.json'),
|
|
29
29
|
legacy: path.join(OPENCODE_CONFIG_DIR, 'config.json')
|
|
30
30
|
};
|
|
31
|
+
const OMP_MCP_CONFIG_PATH = NATIVE_PATHS.omp?.mcp
|
|
32
|
+
|| path.join(NATIVE_PATHS.omp?.dir || path.join(HOME_DIR, '.omp', 'agent'), 'mcp.json');
|
|
31
33
|
|
|
32
34
|
// MCP 客户端连接池
|
|
33
35
|
// serverId -> { client, timestamp }
|
|
@@ -36,6 +38,9 @@ const POOL_TTL = 5 * 60 * 1000; // 5 minutes
|
|
|
36
38
|
const STREAMABLE_HTTP_TYPE = 'streamable_http';
|
|
37
39
|
const MCP_SERVER_TYPES = ['stdio', STREAMABLE_HTTP_TYPE, 'sse'];
|
|
38
40
|
const REMOTE_MCP_SERVER_TYPES = [STREAMABLE_HTTP_TYPE, 'sse'];
|
|
41
|
+
const MCP_PLATFORM_KEYS = ['claude', 'codex', 'gemini', 'opencode', 'omp'];
|
|
42
|
+
const OMP_MCP_SCHEMA_URL = 'https://raw.githubusercontent.com/can1357/oh-my-omp/main/packages/coding-agent/src/config/mcp-schema.json';
|
|
43
|
+
const OMP_SERVER_NAME_PATTERN = /^[a-zA-Z0-9_.-]{1,100}$/;
|
|
39
44
|
|
|
40
45
|
function normalizeServerSpec(spec = {}) {
|
|
41
46
|
if (!spec || typeof spec !== 'object') {
|
|
@@ -532,7 +537,8 @@ const DEFAULT_SERVER_APPS = {
|
|
|
532
537
|
claude: true,
|
|
533
538
|
codex: false,
|
|
534
539
|
gemini: false,
|
|
535
|
-
opencode: false
|
|
540
|
+
opencode: false,
|
|
541
|
+
omp: false
|
|
536
542
|
};
|
|
537
543
|
|
|
538
544
|
function normalizeServerApps(apps = {}, fallbackApps = DEFAULT_SERVER_APPS) {
|
|
@@ -540,7 +546,8 @@ function normalizeServerApps(apps = {}, fallbackApps = DEFAULT_SERVER_APPS) {
|
|
|
540
546
|
claude: apps.claude !== undefined ? !!apps.claude : !!fallbackApps.claude,
|
|
541
547
|
codex: apps.codex !== undefined ? !!apps.codex : !!fallbackApps.codex,
|
|
542
548
|
gemini: apps.gemini !== undefined ? !!apps.gemini : !!fallbackApps.gemini,
|
|
543
|
-
opencode: apps.opencode !== undefined ? !!apps.opencode : !!fallbackApps.opencode
|
|
549
|
+
opencode: apps.opencode !== undefined ? !!apps.opencode : !!fallbackApps.opencode,
|
|
550
|
+
omp: apps.omp !== undefined ? !!apps.omp: !!fallbackApps.omp
|
|
544
551
|
};
|
|
545
552
|
}
|
|
546
553
|
|
|
@@ -648,7 +655,7 @@ async function toggleServerApp(serverId, app, enabled) {
|
|
|
648
655
|
throw new Error(`MCP 服务器 "${serverId}" 不存在`);
|
|
649
656
|
}
|
|
650
657
|
|
|
651
|
-
if (!
|
|
658
|
+
if (!MCP_PLATFORM_KEYS.includes(app)) {
|
|
652
659
|
throw new Error(`无效的平台: ${app}`);
|
|
653
660
|
}
|
|
654
661
|
|
|
@@ -720,28 +727,12 @@ async function syncServerToAllPlatforms(server, previousApps = null) {
|
|
|
720
727
|
return previous[platform] && !apps[platform];
|
|
721
728
|
};
|
|
722
729
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
if (apps.codex) {
|
|
730
|
-
await syncServerToPlatform(server, 'codex');
|
|
731
|
-
} else if (shouldRemoveFromPlatform('codex')) {
|
|
732
|
-
await removeServerFromPlatform(server.id, 'codex');
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
if (apps.gemini) {
|
|
736
|
-
await syncServerToPlatform(server, 'gemini');
|
|
737
|
-
} else if (shouldRemoveFromPlatform('gemini')) {
|
|
738
|
-
await removeServerFromPlatform(server.id, 'gemini');
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
if (apps.opencode) {
|
|
742
|
-
await syncServerToPlatform(server, 'opencode');
|
|
743
|
-
} else if (shouldRemoveFromPlatform('opencode')) {
|
|
744
|
-
await removeServerFromPlatform(server.id, 'opencode');
|
|
730
|
+
for (const platform of MCP_PLATFORM_KEYS) {
|
|
731
|
+
if (apps[platform]) {
|
|
732
|
+
await syncServerToPlatform(server, platform);
|
|
733
|
+
} else if (shouldRemoveFromPlatform(platform)) {
|
|
734
|
+
await removeServerFromPlatform(server.id, platform);
|
|
735
|
+
}
|
|
745
736
|
}
|
|
746
737
|
}
|
|
747
738
|
|
|
@@ -749,10 +740,9 @@ async function syncServerToAllPlatforms(server, previousApps = null) {
|
|
|
749
740
|
* 从所有平台移除服务器
|
|
750
741
|
*/
|
|
751
742
|
async function removeServerFromAllPlatforms(serverId) {
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
await removeServerFromPlatform(serverId, 'opencode');
|
|
743
|
+
for (const platform of MCP_PLATFORM_KEYS) {
|
|
744
|
+
await removeServerFromPlatform(serverId, platform);
|
|
745
|
+
}
|
|
756
746
|
}
|
|
757
747
|
|
|
758
748
|
/**
|
|
@@ -773,6 +763,9 @@ async function syncServerToPlatform(server, platform) {
|
|
|
773
763
|
case 'opencode':
|
|
774
764
|
syncToOpenCodeConfig(server);
|
|
775
765
|
break;
|
|
766
|
+
case 'omp':
|
|
767
|
+
syncToOmpMcpConfig(server);
|
|
768
|
+
break;
|
|
776
769
|
}
|
|
777
770
|
console.log(`[MCP] Synced "${server.id}" to ${platform}`);
|
|
778
771
|
} catch (err) {
|
|
@@ -799,6 +792,9 @@ async function removeServerFromPlatform(serverId, platform) {
|
|
|
799
792
|
case 'opencode':
|
|
800
793
|
removeFromOpenCodeConfig(serverId);
|
|
801
794
|
break;
|
|
795
|
+
case 'omp':
|
|
796
|
+
removeFromOmpMcpConfig(serverId);
|
|
797
|
+
break;
|
|
802
798
|
}
|
|
803
799
|
console.log(`[MCP] Removed "${serverId}" from ${platform}`);
|
|
804
800
|
} catch (err) {
|
|
@@ -947,6 +943,133 @@ function removeFromGeminiConfig(serverId) {
|
|
|
947
943
|
}
|
|
948
944
|
}
|
|
949
945
|
|
|
946
|
+
// ============================================================================
|
|
947
|
+
// OMP 配置同步
|
|
948
|
+
// ============================================================================
|
|
949
|
+
|
|
950
|
+
function validateOmpServerName(serverId) {
|
|
951
|
+
if (!OMP_SERVER_NAME_PATTERN.test(serverId)) {
|
|
952
|
+
throw new Error(`OMP MCP 服务器 ID "${serverId}" 无效。OMP 仅支持 1-100 个字母、数字、下划线、点或连字符。`);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
function readOmpMcpConfig() {
|
|
957
|
+
const config = readJsonFile(OMP_MCP_CONFIG_PATH, { mcpServers: {} });
|
|
958
|
+
if (!config || typeof config !== 'object' || Array.isArray(config)) {
|
|
959
|
+
return { mcpServers: {} };
|
|
960
|
+
}
|
|
961
|
+
if (!config.mcpServers || typeof config.mcpServers !== 'object' || Array.isArray(config.mcpServers)) {
|
|
962
|
+
config.mcpServers = {};
|
|
963
|
+
}
|
|
964
|
+
return config;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
function copyCommonMcpFields(source, target) {
|
|
968
|
+
for (const key of ['timeout', 'auth', 'oauth']) {
|
|
969
|
+
if (source[key] !== undefined) {
|
|
970
|
+
target[key] = source[key];
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
return target;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
function convertToOmpMcpFormat(spec = {}) {
|
|
977
|
+
const sourceType = spec.type || 'stdio';
|
|
978
|
+
let result;
|
|
979
|
+
|
|
980
|
+
if (sourceType === 'stdio') {
|
|
981
|
+
result = {
|
|
982
|
+
type: 'stdio',
|
|
983
|
+
command: spec.command || ''
|
|
984
|
+
};
|
|
985
|
+
if (Array.isArray(spec.args) && spec.args.length > 0) {
|
|
986
|
+
result.args = spec.args;
|
|
987
|
+
}
|
|
988
|
+
if (spec.env && Object.keys(spec.env).length > 0) {
|
|
989
|
+
result.env = spec.env;
|
|
990
|
+
}
|
|
991
|
+
if (spec.cwd) {
|
|
992
|
+
result.cwd = spec.cwd;
|
|
993
|
+
}
|
|
994
|
+
} else if (sourceType === STREAMABLE_HTTP_TYPE) {
|
|
995
|
+
result = {
|
|
996
|
+
type: 'http',
|
|
997
|
+
url: spec.url || ''
|
|
998
|
+
};
|
|
999
|
+
if (spec.headers && Object.keys(spec.headers).length > 0) {
|
|
1000
|
+
result.headers = spec.headers;
|
|
1001
|
+
}
|
|
1002
|
+
} else if (sourceType === 'sse') {
|
|
1003
|
+
result = {
|
|
1004
|
+
type: 'sse',
|
|
1005
|
+
url: spec.url || ''
|
|
1006
|
+
};
|
|
1007
|
+
if (spec.headers && Object.keys(spec.headers).length > 0) {
|
|
1008
|
+
result.headers = spec.headers;
|
|
1009
|
+
}
|
|
1010
|
+
} else {
|
|
1011
|
+
result = extractServerSpec(spec);
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
return copyCommonMcpFields(spec, result);
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
function convertFromOmpMcpFormat(spec = {}) {
|
|
1018
|
+
const sourceType = spec.type || 'stdio';
|
|
1019
|
+
let result;
|
|
1020
|
+
|
|
1021
|
+
if (sourceType === 'stdio') {
|
|
1022
|
+
result = {
|
|
1023
|
+
type: 'stdio',
|
|
1024
|
+
command: spec.command || ''
|
|
1025
|
+
};
|
|
1026
|
+
if (spec.args) {
|
|
1027
|
+
result.args = spec.args;
|
|
1028
|
+
}
|
|
1029
|
+
if (spec.env) {
|
|
1030
|
+
result.env = spec.env;
|
|
1031
|
+
}
|
|
1032
|
+
if (spec.cwd) {
|
|
1033
|
+
result.cwd = spec.cwd;
|
|
1034
|
+
}
|
|
1035
|
+
} else if (sourceType === 'http') {
|
|
1036
|
+
result = {
|
|
1037
|
+
type: STREAMABLE_HTTP_TYPE,
|
|
1038
|
+
url: spec.url || ''
|
|
1039
|
+
};
|
|
1040
|
+
if (spec.headers) {
|
|
1041
|
+
result.headers = spec.headers;
|
|
1042
|
+
}
|
|
1043
|
+
} else if (sourceType === 'sse') {
|
|
1044
|
+
result = {
|
|
1045
|
+
type: 'sse',
|
|
1046
|
+
url: spec.url || ''
|
|
1047
|
+
};
|
|
1048
|
+
if (spec.headers) {
|
|
1049
|
+
result.headers = spec.headers;
|
|
1050
|
+
}
|
|
1051
|
+
} else {
|
|
1052
|
+
result = convertFromCodexFormat(spec);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
return copyCommonMcpFields(spec, result);
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
function syncToOmpMcpConfig(server) {
|
|
1059
|
+
validateOmpServerName(server.id);
|
|
1060
|
+
const config = readOmpMcpConfig();
|
|
1061
|
+
config.mcpServers[server.id] = convertToOmpMcpFormat(server.server);
|
|
1062
|
+
writeJsonFile(OMP_MCP_CONFIG_PATH, config);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
function removeFromOmpMcpConfig(serverId) {
|
|
1066
|
+
const config = readOmpMcpConfig();
|
|
1067
|
+
if (config.mcpServers && config.mcpServers[serverId]) {
|
|
1068
|
+
delete config.mcpServers[serverId];
|
|
1069
|
+
writeJsonFile(OMP_MCP_CONFIG_PATH, config);
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
|
|
950
1073
|
// ============================================================================
|
|
951
1074
|
// OpenCode 配置同步
|
|
952
1075
|
// ============================================================================
|
|
@@ -1108,6 +1231,9 @@ async function importFromPlatform(platform) {
|
|
|
1108
1231
|
case 'opencode':
|
|
1109
1232
|
importedCount = importFromOpenCode(servers);
|
|
1110
1233
|
break;
|
|
1234
|
+
case 'omp':
|
|
1235
|
+
importedCount = importFromOmp(servers);
|
|
1236
|
+
break;
|
|
1111
1237
|
default:
|
|
1112
1238
|
throw new Error(`无效的平台: ${platform}`);
|
|
1113
1239
|
}
|
|
@@ -1250,6 +1376,39 @@ function importFromOpenCode(servers) {
|
|
|
1250
1376
|
return count;
|
|
1251
1377
|
}
|
|
1252
1378
|
|
|
1379
|
+
/**
|
|
1380
|
+
* 从 OMP 导入
|
|
1381
|
+
*/
|
|
1382
|
+
function importFromOmp(servers) {
|
|
1383
|
+
const config = readOmpMcpConfig();
|
|
1384
|
+
const mcpServers = config.mcpServers || {};
|
|
1385
|
+
let count = 0;
|
|
1386
|
+
|
|
1387
|
+
for (const [id, spec] of Object.entries(mcpServers)) {
|
|
1388
|
+
const convertedSpec = convertFromOmpMcpFormat(spec || {});
|
|
1389
|
+
|
|
1390
|
+
if (servers[id]) {
|
|
1391
|
+
servers[id].apps = normalizeServerApps(servers[id].apps);
|
|
1392
|
+
if (!servers[id].apps.omp) {
|
|
1393
|
+
servers[id].apps.omp = true;
|
|
1394
|
+
count++;
|
|
1395
|
+
}
|
|
1396
|
+
} else {
|
|
1397
|
+
servers[id] = {
|
|
1398
|
+
id,
|
|
1399
|
+
name: id,
|
|
1400
|
+
server: convertedSpec,
|
|
1401
|
+
apps: { claude: false, codex: false, gemini: false, opencode: false, omp: true },
|
|
1402
|
+
createdAt: Date.now(),
|
|
1403
|
+
updatedAt: Date.now()
|
|
1404
|
+
};
|
|
1405
|
+
count++;
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
return count;
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1253
1412
|
/**
|
|
1254
1413
|
* 从 Codex 格式转换
|
|
1255
1414
|
*/
|
|
@@ -1311,7 +1470,8 @@ function getStats() {
|
|
|
1311
1470
|
claude: serverList.filter(s => s.apps?.claude).length,
|
|
1312
1471
|
codex: serverList.filter(s => s.apps?.codex).length,
|
|
1313
1472
|
gemini: serverList.filter(s => s.apps?.gemini).length,
|
|
1314
|
-
opencode: serverList.filter(s => s.apps?.opencode).length
|
|
1473
|
+
opencode: serverList.filter(s => s.apps?.opencode).length,
|
|
1474
|
+
omp: serverList.filter(s => s.apps?.omp).length
|
|
1315
1475
|
};
|
|
1316
1476
|
}
|
|
1317
1477
|
|
|
@@ -1763,7 +1923,7 @@ function updateServerOrder(serverIds) {
|
|
|
1763
1923
|
|
|
1764
1924
|
/**
|
|
1765
1925
|
* 导出所有 MCP 配置
|
|
1766
|
-
* @param {string} format - 导出格式: 'json' | 'claude' | 'codex' | 'opencode' | 'gemini'
|
|
1926
|
+
* @param {string} format - 导出格式: 'json' | 'claude' | 'codex' | 'opencode' | 'gemini' | 'omp'
|
|
1767
1927
|
*/
|
|
1768
1928
|
function exportServers(format = 'json') {
|
|
1769
1929
|
const servers = getAllServers();
|
|
@@ -1777,6 +1937,8 @@ function exportServers(format = 'json') {
|
|
|
1777
1937
|
return exportForOpenCode(servers);
|
|
1778
1938
|
case 'gemini':
|
|
1779
1939
|
return exportForGemini(servers);
|
|
1940
|
+
case 'omp':
|
|
1941
|
+
return exportForOmp(servers);
|
|
1780
1942
|
case 'json':
|
|
1781
1943
|
default:
|
|
1782
1944
|
return exportAsJson(servers);
|
|
@@ -1876,6 +2038,26 @@ function exportForGemini(servers) {
|
|
|
1876
2038
|
};
|
|
1877
2039
|
}
|
|
1878
2040
|
|
|
2041
|
+
/**
|
|
2042
|
+
* 导出为 OMP 格式
|
|
2043
|
+
*/
|
|
2044
|
+
function exportForOmp(servers) {
|
|
2045
|
+
const mcpServers = {};
|
|
2046
|
+
|
|
2047
|
+
for (const [id, server] of Object.entries(servers)) {
|
|
2048
|
+
if (server.apps?.omp) {
|
|
2049
|
+
validateOmpServerName(id);
|
|
2050
|
+
mcpServers[id] = convertToOmpMcpFormat(server.server);
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
return {
|
|
2055
|
+
format: 'omp',
|
|
2056
|
+
content: JSON.stringify({ $schema: OMP_MCP_SCHEMA_URL, mcpServers }, null, 2),
|
|
2057
|
+
filename: 'omp-mcp-config.json'
|
|
2058
|
+
};
|
|
2059
|
+
}
|
|
2060
|
+
|
|
1879
2061
|
module.exports = {
|
|
1880
2062
|
getAllServers,
|
|
1881
2063
|
getServer,
|
|
@@ -1895,6 +2077,8 @@ module.exports = {
|
|
|
1895
2077
|
exportServers,
|
|
1896
2078
|
_test: {
|
|
1897
2079
|
extractMcpHint,
|
|
1898
|
-
buildMcpFailureResult
|
|
2080
|
+
buildMcpFailureResult,
|
|
2081
|
+
convertToOmpMcpFormat,
|
|
2082
|
+
convertFromOmpMcpFormat
|
|
1899
2083
|
}
|
|
1900
2084
|
};
|
|
@@ -13,6 +13,7 @@ const geminiSettingsManager = require('./gemini-settings-manager');
|
|
|
13
13
|
|
|
14
14
|
const MANAGED_HOOK_NAME = 'coding-tool-notify';
|
|
15
15
|
const MANAGED_OPENCODE_PLUGIN_FILE = 'coding-tool-notify.js';
|
|
16
|
+
const MANAGED_OMP_EXTENSION_FILE = 'coding-tool-notify.ts';
|
|
16
17
|
const REMOTE_PROVIDER_TYPES = [
|
|
17
18
|
'wechatBot',
|
|
18
19
|
'qqBot',
|
|
@@ -371,6 +372,13 @@ function getOpenCodeManagedPluginPath() {
|
|
|
371
372
|
return path.join(NATIVE_PATHS.opencode.config, 'plugins', MANAGED_OPENCODE_PLUGIN_FILE);
|
|
372
373
|
}
|
|
373
374
|
|
|
375
|
+
function getOmpManagedExtensionPath() {
|
|
376
|
+
const ompPaths = NATIVE_PATHS.omp || {};
|
|
377
|
+
const extensionsDir = ompPaths.extensions ||
|
|
378
|
+
path.join(ompPaths.dir || path.dirname(ompPaths.settings || PATHS.notifyHook), 'extensions');
|
|
379
|
+
return path.join(extensionsDir, MANAGED_OMP_EXTENSION_FILE);
|
|
380
|
+
}
|
|
381
|
+
|
|
374
382
|
function buildOpenCodePluginContent(type) {
|
|
375
383
|
const mode = normalizeType(type);
|
|
376
384
|
return `// Managed by Coding Tool. Do not edit manually.
|
|
@@ -410,6 +418,64 @@ export const CodingToolNotifyPlugin = async () => ({
|
|
|
410
418
|
`;
|
|
411
419
|
}
|
|
412
420
|
|
|
421
|
+
function buildOmpExtensionContent(type) {
|
|
422
|
+
const mode = normalizeType(type);
|
|
423
|
+
return `// Managed by Coding Tool. Do not edit manually.
|
|
424
|
+
// mode:${mode}
|
|
425
|
+
import { spawn } from 'node:child_process'
|
|
426
|
+
|
|
427
|
+
const SCRIPT_PATH = ${JSON.stringify(PATHS.notifyHook)}
|
|
428
|
+
const MODE = ${JSON.stringify(mode)}
|
|
429
|
+
let lastFireAt = 0
|
|
430
|
+
|
|
431
|
+
function shouldFire() {
|
|
432
|
+
const now = Date.now()
|
|
433
|
+
if (now - lastFireAt < 1000) {
|
|
434
|
+
return false
|
|
435
|
+
}
|
|
436
|
+
lastFireAt = now
|
|
437
|
+
return true
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function fire(eventType) {
|
|
441
|
+
if (!shouldFire()) {
|
|
442
|
+
return
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
try {
|
|
446
|
+
const child = spawn('node', [
|
|
447
|
+
SCRIPT_PATH,
|
|
448
|
+
'--source=omp',
|
|
449
|
+
\`--mode=\${MODE}\`,
|
|
450
|
+
\`--cc-notify-type=\${MODE}\`,
|
|
451
|
+
\`--event-type=\${eventType}\`
|
|
452
|
+
], {
|
|
453
|
+
detached: true,
|
|
454
|
+
stdio: 'ignore',
|
|
455
|
+
windowsHide: true
|
|
456
|
+
})
|
|
457
|
+
child.unref()
|
|
458
|
+
} catch (error) {
|
|
459
|
+
// Ignore notification failures.
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
export default async function CodingToolNotifyExtension(omp) {
|
|
464
|
+
const register = (eventName) => {
|
|
465
|
+
if (typeof omp?.on !== 'function') {
|
|
466
|
+
return
|
|
467
|
+
}
|
|
468
|
+
omp.on(eventName, async () => {
|
|
469
|
+
fire(eventName)
|
|
470
|
+
})
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
register('agent_settled')
|
|
474
|
+
register('turn_end')
|
|
475
|
+
}
|
|
476
|
+
`;
|
|
477
|
+
}
|
|
478
|
+
|
|
413
479
|
function escapeForAppleScript(value) {
|
|
414
480
|
return String(value || '').replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
415
481
|
}
|
|
@@ -712,6 +778,10 @@ function resolveMessage(source, eventType, payload) {
|
|
|
712
778
|
return 'OpenCode 响应已完成 | 等待交互'
|
|
713
779
|
}
|
|
714
780
|
|
|
781
|
+
if (source === 'omp') {
|
|
782
|
+
return 'OMP 回合已完成 | 等待交互'
|
|
783
|
+
}
|
|
784
|
+
|
|
715
785
|
return 'Claude Code 任务已完成 | 等待交互'
|
|
716
786
|
}
|
|
717
787
|
|
|
@@ -886,12 +956,17 @@ function sendTelegramMessage(config = {}, ctx, send = postJson) {
|
|
|
886
956
|
return send(url, payload, {}, agent ? { agent } : {})
|
|
887
957
|
}
|
|
888
958
|
|
|
959
|
+
function resolveDisplaySource(source) {
|
|
960
|
+
if (source === 'omp') return 'OMP'
|
|
961
|
+
return source
|
|
962
|
+
}
|
|
963
|
+
|
|
889
964
|
function buildNotificationContext(message, source, eventType) {
|
|
890
965
|
const timestamp = new Date().toLocaleString('zh-CN')
|
|
891
966
|
return {
|
|
892
967
|
title: 'Coding Tool - 通知',
|
|
893
968
|
message,
|
|
894
|
-
source,
|
|
969
|
+
source: resolveDisplaySource(source),
|
|
895
970
|
eventType,
|
|
896
971
|
timestamp,
|
|
897
972
|
hostname: os.hostname()
|
|
@@ -1545,6 +1620,24 @@ function parseOpenCodeNotificationStatus(content = '') {
|
|
|
1545
1620
|
};
|
|
1546
1621
|
}
|
|
1547
1622
|
|
|
1623
|
+
function parseOmpNotificationStatus(content = '') {
|
|
1624
|
+
if (!content) {
|
|
1625
|
+
return {
|
|
1626
|
+
enabled: false,
|
|
1627
|
+
external: false,
|
|
1628
|
+
type: 'notification',
|
|
1629
|
+
method: 'Extension Events'
|
|
1630
|
+
};
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
return {
|
|
1634
|
+
enabled: true,
|
|
1635
|
+
external: false,
|
|
1636
|
+
type: parseManagedType(content) || 'notification',
|
|
1637
|
+
method: 'Extension Events'
|
|
1638
|
+
};
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1548
1641
|
function getOpenCodeHookStatus() {
|
|
1549
1642
|
const pluginPath = getOpenCodeManagedPluginPath();
|
|
1550
1643
|
if (!fs.existsSync(pluginPath)) {
|
|
@@ -1554,6 +1647,15 @@ function getOpenCodeHookStatus() {
|
|
|
1554
1647
|
return parseOpenCodeNotificationStatus(fs.readFileSync(pluginPath, 'utf8'));
|
|
1555
1648
|
}
|
|
1556
1649
|
|
|
1650
|
+
function getOmpHookStatus() {
|
|
1651
|
+
const extensionPath = getOmpManagedExtensionPath();
|
|
1652
|
+
if (!fs.existsSync(extensionPath)) {
|
|
1653
|
+
return parseOmpNotificationStatus('');
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
return parseOmpNotificationStatus(fs.readFileSync(extensionPath, 'utf8'));
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1557
1659
|
function saveOpenCodeHook(enabled, type) {
|
|
1558
1660
|
const pluginPath = getOpenCodeManagedPluginPath();
|
|
1559
1661
|
const opencodeSettingsManager = require('./opencode-settings-manager');
|
|
@@ -1608,6 +1710,20 @@ function saveOpenCodeHook(enabled, type) {
|
|
|
1608
1710
|
}
|
|
1609
1711
|
}
|
|
1610
1712
|
|
|
1713
|
+
function saveOmpHook(enabled, type) {
|
|
1714
|
+
const extensionPath = getOmpManagedExtensionPath();
|
|
1715
|
+
|
|
1716
|
+
if (!enabled) {
|
|
1717
|
+
if (fs.existsSync(extensionPath)) {
|
|
1718
|
+
fs.unlinkSync(extensionPath);
|
|
1719
|
+
}
|
|
1720
|
+
return;
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
ensureParentDir(extensionPath);
|
|
1724
|
+
fs.writeFileSync(extensionPath, buildOmpExtensionContent(type), 'utf8');
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1611
1727
|
function getNotificationSettings() {
|
|
1612
1728
|
const uiConfig = loadUIConfig();
|
|
1613
1729
|
const remoteNotifications = getRemoteNotificationsConfig(uiConfig);
|
|
@@ -1623,7 +1739,8 @@ function getNotificationSettings() {
|
|
|
1623
1739
|
claude: getClaudeHookStatus(),
|
|
1624
1740
|
codex: getCodexHookStatus(),
|
|
1625
1741
|
gemini: getGeminiHookStatus(),
|
|
1626
|
-
opencode: getOpenCodeHookStatus()
|
|
1742
|
+
opencode: getOpenCodeHookStatus(),
|
|
1743
|
+
omp: getOmpHookStatus()
|
|
1627
1744
|
}
|
|
1628
1745
|
};
|
|
1629
1746
|
}
|
|
@@ -1643,6 +1760,8 @@ function resolveBrowserNotificationTitle(source = 'claude') {
|
|
|
1643
1760
|
return 'Gemini CLI';
|
|
1644
1761
|
case 'opencode':
|
|
1645
1762
|
return 'OpenCode';
|
|
1763
|
+
case 'omp':
|
|
1764
|
+
return 'OMP';
|
|
1646
1765
|
default:
|
|
1647
1766
|
return 'Claude Code';
|
|
1648
1767
|
}
|
|
@@ -1656,6 +1775,8 @@ function resolveBrowserNotificationUrl(source = 'claude') {
|
|
|
1656
1775
|
return '/gemini';
|
|
1657
1776
|
case 'opencode':
|
|
1658
1777
|
return '/opencode';
|
|
1778
|
+
case 'omp':
|
|
1779
|
+
return '/omp';
|
|
1659
1780
|
default:
|
|
1660
1781
|
return '/claude';
|
|
1661
1782
|
}
|
|
@@ -1694,7 +1815,8 @@ function saveNotificationSettings(input = {}) {
|
|
|
1694
1815
|
claude: normalizePlatformInput(input?.platforms?.claude),
|
|
1695
1816
|
codex: normalizePlatformInput(input?.platforms?.codex),
|
|
1696
1817
|
gemini: normalizePlatformInput(input?.platforms?.gemini),
|
|
1697
|
-
opencode: normalizePlatformInput(input?.platforms?.opencode)
|
|
1818
|
+
opencode: normalizePlatformInput(input?.platforms?.opencode),
|
|
1819
|
+
omp: normalizePlatformInput(input?.platforms?.omp)
|
|
1698
1820
|
};
|
|
1699
1821
|
|
|
1700
1822
|
saveNotificationUiConfig(remoteNotifications, platforms.claude.enabled);
|
|
@@ -1708,6 +1830,7 @@ function saveNotificationSettings(input = {}) {
|
|
|
1708
1830
|
saveCodexHook(platforms.codex.enabled, platforms.codex.type);
|
|
1709
1831
|
saveGeminiHook(platforms.gemini.enabled, platforms.gemini.type);
|
|
1710
1832
|
saveOpenCodeHook(platforms.opencode.enabled, platforms.opencode.type);
|
|
1833
|
+
saveOmpHook(platforms.omp.enabled, platforms.omp.type);
|
|
1711
1834
|
|
|
1712
1835
|
if (!hasManagedPlatform) {
|
|
1713
1836
|
removeNotifyScript();
|
|
@@ -1834,7 +1957,8 @@ function buildLegacyClaudeSaveInput(input = {}, currentSettings = getNotificatio
|
|
|
1834
1957
|
: { enabled: false, type: 'notification' },
|
|
1835
1958
|
codex: normalizeSavedPlatformStatus(currentSettings?.platforms?.codex),
|
|
1836
1959
|
gemini: normalizeSavedPlatformStatus(currentSettings?.platforms?.gemini),
|
|
1837
|
-
opencode: normalizeSavedPlatformStatus(currentSettings?.platforms?.opencode)
|
|
1960
|
+
opencode: normalizeSavedPlatformStatus(currentSettings?.platforms?.opencode),
|
|
1961
|
+
omp: normalizeSavedPlatformStatus(currentSettings?.platforms?.omp)
|
|
1838
1962
|
},
|
|
1839
1963
|
remoteNotifications: currentSettings?.remoteNotifications || { providers: [] }
|
|
1840
1964
|
};
|
|
@@ -1873,7 +1997,8 @@ function initDefaultHooks() {
|
|
|
1873
1997
|
claude: { enabled: true, type: currentStatus.type || 'notification' },
|
|
1874
1998
|
codex: normalizeSavedPlatformStatus(currentSettings?.platforms?.codex),
|
|
1875
1999
|
gemini: normalizeSavedPlatformStatus(currentSettings?.platforms?.gemini),
|
|
1876
|
-
opencode: normalizeSavedPlatformStatus(currentSettings?.platforms?.opencode)
|
|
2000
|
+
opencode: normalizeSavedPlatformStatus(currentSettings?.platforms?.opencode),
|
|
2001
|
+
omp: normalizeSavedPlatformStatus(currentSettings?.platforms?.omp)
|
|
1877
2002
|
},
|
|
1878
2003
|
remoteNotifications: currentSettings?.remoteNotifications || { providers: [] }
|
|
1879
2004
|
});
|
|
@@ -1890,7 +2015,8 @@ function initDefaultHooks() {
|
|
|
1890
2015
|
claude: { enabled: true, type: 'notification' },
|
|
1891
2016
|
codex: normalizeSavedPlatformStatus(currentSettings?.platforms?.codex),
|
|
1892
2017
|
gemini: normalizeSavedPlatformStatus(currentSettings?.platforms?.gemini),
|
|
1893
|
-
opencode: normalizeSavedPlatformStatus(currentSettings?.platforms?.opencode)
|
|
2018
|
+
opencode: normalizeSavedPlatformStatus(currentSettings?.platforms?.opencode),
|
|
2019
|
+
omp: normalizeSavedPlatformStatus(currentSettings?.platforms?.omp)
|
|
1894
2020
|
},
|
|
1895
2021
|
remoteNotifications: currentSettings?.remoteNotifications || { providers: [] }
|
|
1896
2022
|
});
|
|
@@ -2277,7 +2403,9 @@ module.exports = {
|
|
|
2277
2403
|
initDefaultHooks,
|
|
2278
2404
|
syncManagedNotificationAssets,
|
|
2279
2405
|
getOpenCodeManagedPluginPath,
|
|
2406
|
+
getOmpManagedExtensionPath,
|
|
2280
2407
|
buildOpenCodePluginContent,
|
|
2408
|
+
buildOmpExtensionContent,
|
|
2281
2409
|
buildCodexNotifyCommand,
|
|
2282
2410
|
writeNotifyScript,
|
|
2283
2411
|
generateNotifyScript,
|
|
@@ -2292,9 +2420,11 @@ module.exports = {
|
|
|
2292
2420
|
getCodexHookStatus,
|
|
2293
2421
|
getGeminiHookStatus,
|
|
2294
2422
|
getOpenCodeHookStatus,
|
|
2423
|
+
getOmpHookStatus,
|
|
2295
2424
|
parseCodexNotificationStatus,
|
|
2296
2425
|
parseGeminiNotificationStatus,
|
|
2297
2426
|
parseOpenCodeNotificationStatus,
|
|
2427
|
+
parseOmpNotificationStatus,
|
|
2298
2428
|
validateFeishuWebhookUrl,
|
|
2299
2429
|
normalizeRemoteNotificationsConfig,
|
|
2300
2430
|
validateRemoteProviderConfig,
|
|
@@ -2303,7 +2433,9 @@ module.exports = {
|
|
|
2303
2433
|
buildStopHookCommand,
|
|
2304
2434
|
buildClaudeCommand,
|
|
2305
2435
|
buildOpenCodePluginContent,
|
|
2436
|
+
buildOmpExtensionContent,
|
|
2306
2437
|
getOpenCodeManagedPluginPath,
|
|
2438
|
+
getOmpManagedExtensionPath,
|
|
2307
2439
|
generateNotifyScript,
|
|
2308
2440
|
generateSystemNotificationCommand,
|
|
2309
2441
|
emitBrowserNotification,
|