coding-tool-x 3.7.0 → 3.7.2
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 +10 -11
- package/dist/web/assets/{Analytics-Dma_j2Rq.js → Analytics-D5kLOhUo.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-C49Y1PLH.js → ConfigTemplates-D_-16blp.js} +1 -1
- package/dist/web/assets/Home-DM_56Fyr.js +1 -0
- package/dist/web/assets/Home-Jom_ZcdY.css +1 -0
- package/dist/web/assets/{PluginManager-B1ECTHyY.js → PluginManager-Cv_rv8Dh.js} +1 -1
- package/dist/web/assets/{ProjectList-B_L55-l9.css → ProjectList-D3a0oRum.css} +1 -1
- package/dist/web/assets/ProjectList-H_m4Tx4E.js +1 -0
- package/dist/web/assets/{SessionList-CH5GwwiJ.js → SessionList-DcUQvsbR.js} +1 -1
- package/dist/web/assets/{SkillManager-CRyVhjYQ.js → SkillManager-CRav3m2a.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-CO9tclVt.js → WorkspaceManager-B3f8R4EF.js} +1 -1
- package/dist/web/assets/index-Bnni1zPN.js +2 -0
- package/dist/web/assets/index-CfMuHG8u.css +1 -0
- 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/commands/ui.js +1 -0
- package/src/config/default.js +3 -3
- package/src/config/paths.js +46 -49
- package/src/index.js +7 -7
- 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/oauth-credentials.js +15 -2
- package/src/server/api/{pi-channels.js → omp-channels.js} +115 -53
- 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 +23 -15
- 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/model-detector.js +15 -2
- package/src/server/services/native-oauth-adapters.js +212 -1
- package/src/server/services/network-access.js +5 -0
- package/src/server/services/notification-hooks.js +138 -6
- package/src/server/services/oauth-credentials-service.js +110 -3
- package/src/server/services/{pi-auth-providers.js → omp-auth-providers.js} +2 -2
- package/src/server/services/{pi-channels.js → omp-channels.js} +10 -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-CM26UrnJ.css +0 -1
- package/dist/web/assets/index-EQq56pRa.js +0 -2
|
@@ -2,6 +2,7 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const os = require('os');
|
|
4
4
|
const crypto = require('crypto');
|
|
5
|
+
const { spawnSync } = require('child_process');
|
|
5
6
|
const toml = require('toml');
|
|
6
7
|
const tomlStringify = require('@iarna/toml').stringify;
|
|
7
8
|
const { NATIVE_PATHS, PATHS } = require('../../config/paths');
|
|
@@ -13,7 +14,7 @@ const { syncCodexUserEnvironment } = require('./codex-env-manager');
|
|
|
13
14
|
const nativeKeychain = require('./native-keychain');
|
|
14
15
|
const { maskToken, decodeJwtPayload, removeFileIfExists, sha256 } = require('./oauth-utils');
|
|
15
16
|
|
|
16
|
-
const SUPPORTED_TOOLS = ['claude', 'codex', 'gemini', 'opencode'];
|
|
17
|
+
const SUPPORTED_TOOLS = ['claude', 'codex', 'gemini', 'opencode', 'omp'];
|
|
17
18
|
const GEMINI_MAIN_ACCOUNT_KEY = 'main-account';
|
|
18
19
|
const GEMINI_KEYCHAIN_SERVICE = 'gemini-cli-oauth';
|
|
19
20
|
const CODEX_KEYCHAIN_SERVICE = 'Codex Auth';
|
|
@@ -1006,6 +1007,202 @@ function inspectOpenCodeState() {
|
|
|
1006
1007
|
};
|
|
1007
1008
|
}
|
|
1008
1009
|
|
|
1010
|
+
function resolveOmpRuntime() {
|
|
1011
|
+
try {
|
|
1012
|
+
const ompConfig = require('./omp-config');
|
|
1013
|
+
const runtime = ompConfig.resolveOmpRuntime(process.env, {});
|
|
1014
|
+
return runtime && runtime.runtime === 'omp' && runtime.installed ? runtime : null;
|
|
1015
|
+
} catch {
|
|
1016
|
+
return null;
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
function runOmpCommand(args = [], options = {}) {
|
|
1021
|
+
const runtime = options.runtime || resolveOmpRuntime();
|
|
1022
|
+
if (!runtime) {
|
|
1023
|
+
return { ok: false, status: 127, stdout: '', stderr: 'OMP CLI not installed' };
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
const result = spawnSync(runtime.command, args, {
|
|
1027
|
+
encoding: 'utf8',
|
|
1028
|
+
env: {
|
|
1029
|
+
...process.env,
|
|
1030
|
+
...(options.env || {})
|
|
1031
|
+
},
|
|
1032
|
+
timeout: options.timeout || 10000
|
|
1033
|
+
});
|
|
1034
|
+
const status = result?.status === undefined || result?.status === null ? 0 : result.status;
|
|
1035
|
+
return {
|
|
1036
|
+
ok: !result?.error && status === 0,
|
|
1037
|
+
status,
|
|
1038
|
+
stdout: String(result?.stdout || ''),
|
|
1039
|
+
stderr: String(result?.stderr || ''),
|
|
1040
|
+
error: result?.error || null,
|
|
1041
|
+
command: runtime.command
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
function getOmpAuthSnapshot(options = {}) {
|
|
1046
|
+
try {
|
|
1047
|
+
const { getOmpAuthProviderSnapshot } = require('./omp-auth-providers');
|
|
1048
|
+
return getOmpAuthProviderSnapshot({
|
|
1049
|
+
accountCheck: true,
|
|
1050
|
+
includeStatus: false,
|
|
1051
|
+
...options
|
|
1052
|
+
});
|
|
1053
|
+
} catch {
|
|
1054
|
+
return null;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
function readAllOmpNativeOAuth() {
|
|
1059
|
+
const snapshot = getOmpAuthSnapshot({ forceRefresh: true });
|
|
1060
|
+
if (!snapshot?.available || !Array.isArray(snapshot.providers)) {
|
|
1061
|
+
return [];
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
return snapshot.providers
|
|
1065
|
+
.filter(provider => provider?.loggedIn || Number(provider?.accountCount || 0) > 0)
|
|
1066
|
+
.flatMap((provider) => {
|
|
1067
|
+
const accounts = Array.isArray(provider.accounts) && provider.accounts.length > 0
|
|
1068
|
+
? provider.accounts
|
|
1069
|
+
: [{ index: 1, identity: '' }];
|
|
1070
|
+
return accounts.map((account) => ({
|
|
1071
|
+
providerId: provider.id,
|
|
1072
|
+
accountId: String(account.index || '').trim(),
|
|
1073
|
+
accountEmail: String(account.identity || '').trim(),
|
|
1074
|
+
storage: 'auth-broker',
|
|
1075
|
+
primaryToken: ''
|
|
1076
|
+
}));
|
|
1077
|
+
});
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
function readOmpNativeOAuth() {
|
|
1081
|
+
return readAllOmpNativeOAuth()[0] || null;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
function clearOmpOAuth() {
|
|
1085
|
+
const credentials = readAllOmpNativeOAuth();
|
|
1086
|
+
const providerIds = [...new Set(credentials.map(item => item.providerId).filter(Boolean))];
|
|
1087
|
+
providerIds.forEach((providerId) => {
|
|
1088
|
+
runOmpCommand(['auth-broker', 'logout', providerId], { timeout: 10000 });
|
|
1089
|
+
});
|
|
1090
|
+
try {
|
|
1091
|
+
require('./omp-auth-providers').clearOmpAuthProviderCache();
|
|
1092
|
+
} catch {
|
|
1093
|
+
// cache invalidation is best-effort
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
function disableOmpOAuthCredential(credential = {}) {
|
|
1098
|
+
const providerId = String(credential.providerId || '').trim();
|
|
1099
|
+
if (!providerId) {
|
|
1100
|
+
clearOmpOAuth();
|
|
1101
|
+
return;
|
|
1102
|
+
}
|
|
1103
|
+
runOmpCommand(['auth-broker', 'logout', providerId], { timeout: 10000 });
|
|
1104
|
+
try {
|
|
1105
|
+
require('./omp-auth-providers').clearOmpAuthProviderCache();
|
|
1106
|
+
} catch {
|
|
1107
|
+
// cache invalidation is best-effort
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
function buildOmpImportPayload(credential = {}) {
|
|
1112
|
+
if (credential.importPayload && typeof credential.importPayload === 'object') {
|
|
1113
|
+
return credential.importPayload;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
const access = String(credential.accessToken || credential.primaryToken || '').trim();
|
|
1117
|
+
if (!access) {
|
|
1118
|
+
return null;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
return {
|
|
1122
|
+
provider: credential.providerId,
|
|
1123
|
+
credential_type: credential.credentialType || 'oauth',
|
|
1124
|
+
identity_key: credential.identityKey || credential.accountId || credential.accountEmail || undefined,
|
|
1125
|
+
data: {
|
|
1126
|
+
access,
|
|
1127
|
+
refresh: credential.refreshToken || '',
|
|
1128
|
+
expires: credential.expiresAt || null,
|
|
1129
|
+
accountId: credential.accountId || undefined,
|
|
1130
|
+
accountEmail: credential.accountEmail || undefined
|
|
1131
|
+
}
|
|
1132
|
+
};
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
function hasOmpNativeCredential(providerId) {
|
|
1136
|
+
return readAllOmpNativeOAuth().some((entry) => (
|
|
1137
|
+
!providerId || entry.providerId === providerId
|
|
1138
|
+
));
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
function applyOmpOAuth(credential = {}) {
|
|
1142
|
+
const providerId = String(credential.providerId || '').trim();
|
|
1143
|
+
if (!providerId) {
|
|
1144
|
+
throw new Error('OMP OAuth credential requires providerId');
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
const payload = buildOmpImportPayload(credential);
|
|
1148
|
+
if (!payload) {
|
|
1149
|
+
if (hasOmpNativeCredential(providerId)) {
|
|
1150
|
+
return { storage: 'auth-broker-existing' };
|
|
1151
|
+
}
|
|
1152
|
+
throw new Error('OMP OAuth credential requires an import payload or access token');
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ctx-omp-oauth-'));
|
|
1156
|
+
const tempPath = path.join(tempDir, `${providerId}.json`);
|
|
1157
|
+
try {
|
|
1158
|
+
fs.writeFileSync(tempPath, JSON.stringify(payload, null, 2), 'utf8');
|
|
1159
|
+
ensureFileMode(tempPath);
|
|
1160
|
+
const result = runOmpCommand(['auth-broker', 'import', tempPath, '--provider', providerId], { timeout: 15000 });
|
|
1161
|
+
if (!result.ok) {
|
|
1162
|
+
const detail = result.stderr.trim() || result.stdout.trim() || result.error?.message || `exit code ${result.status}`;
|
|
1163
|
+
throw new Error(`OMP auth-broker import failed: ${detail}`);
|
|
1164
|
+
}
|
|
1165
|
+
try {
|
|
1166
|
+
require('./omp-auth-providers').clearOmpAuthProviderCache();
|
|
1167
|
+
} catch {
|
|
1168
|
+
// cache invalidation is best-effort
|
|
1169
|
+
}
|
|
1170
|
+
return { storage: 'auth-broker' };
|
|
1171
|
+
} finally {
|
|
1172
|
+
try {
|
|
1173
|
+
removeFileIfExists(tempPath);
|
|
1174
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
1175
|
+
} catch {
|
|
1176
|
+
// ignore cleanup failures
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
function inspectOmpState() {
|
|
1182
|
+
const { getOmpProxyStatus } = require('../omp-proxy-server');
|
|
1183
|
+
const { isManagedOmpProvidersActive } = require('./omp-settings-manager');
|
|
1184
|
+
const proxyStatus = getOmpProxyStatus();
|
|
1185
|
+
const nativeCredentials = readAllOmpNativeOAuth();
|
|
1186
|
+
|
|
1187
|
+
let channelConfigured = false;
|
|
1188
|
+
try {
|
|
1189
|
+
channelConfigured = Boolean(isManagedOmpProvidersActive());
|
|
1190
|
+
} catch {
|
|
1191
|
+
channelConfigured = false;
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
return {
|
|
1195
|
+
tool: 'omp',
|
|
1196
|
+
mode: proxyStatus.running || channelConfigured
|
|
1197
|
+
? 'proxy'
|
|
1198
|
+
: (nativeCredentials.length > 0 ? 'oauth' : 'idle'),
|
|
1199
|
+
proxyRunning: Boolean(proxyStatus.running || channelConfigured),
|
|
1200
|
+
oauthPresent: nativeCredentials.length > 0,
|
|
1201
|
+
channelConfigured,
|
|
1202
|
+
nativeCredential: nativeCredentials[0] ? buildNativeSummary(nativeCredentials[0]) : null
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1009
1206
|
function inspectTool(tool) {
|
|
1010
1207
|
switch (tool) {
|
|
1011
1208
|
case 'claude':
|
|
@@ -1016,6 +1213,8 @@ function inspectTool(tool) {
|
|
|
1016
1213
|
return inspectGeminiState();
|
|
1017
1214
|
case 'opencode':
|
|
1018
1215
|
return inspectOpenCodeState();
|
|
1216
|
+
case 'omp':
|
|
1217
|
+
return inspectOmpState();
|
|
1019
1218
|
default:
|
|
1020
1219
|
throw new Error(`Unsupported OAuth tool: ${tool}`);
|
|
1021
1220
|
}
|
|
@@ -1031,6 +1230,8 @@ function readNativeOAuth(tool) {
|
|
|
1031
1230
|
return readGeminiNativeOAuth();
|
|
1032
1231
|
case 'opencode':
|
|
1033
1232
|
return readOpenCodeNativeOAuth();
|
|
1233
|
+
case 'omp':
|
|
1234
|
+
return readOmpNativeOAuth();
|
|
1034
1235
|
default:
|
|
1035
1236
|
throw new Error(`Unsupported OAuth tool: ${tool}`);
|
|
1036
1237
|
}
|
|
@@ -1052,6 +1253,8 @@ function readAllNativeOAuth(tool) {
|
|
|
1052
1253
|
}
|
|
1053
1254
|
case 'opencode':
|
|
1054
1255
|
return readAllOpenCodeNativeOAuth();
|
|
1256
|
+
case 'omp':
|
|
1257
|
+
return readAllOmpNativeOAuth();
|
|
1055
1258
|
default:
|
|
1056
1259
|
throw new Error(`Unsupported OAuth tool: ${tool}`);
|
|
1057
1260
|
}
|
|
@@ -1071,6 +1274,9 @@ function clearNativeOAuth(tool) {
|
|
|
1071
1274
|
case 'opencode':
|
|
1072
1275
|
clearOpenCodeOAuth();
|
|
1073
1276
|
return;
|
|
1277
|
+
case 'omp':
|
|
1278
|
+
clearOmpOAuth();
|
|
1279
|
+
return;
|
|
1074
1280
|
default:
|
|
1075
1281
|
throw new Error(`Unsupported OAuth tool: ${tool}`);
|
|
1076
1282
|
}
|
|
@@ -1090,6 +1296,9 @@ function disableNativeOAuthCredential(tool, credential = {}) {
|
|
|
1090
1296
|
case 'opencode':
|
|
1091
1297
|
disableOpenCodeOAuthCredential(credential);
|
|
1092
1298
|
return;
|
|
1299
|
+
case 'omp':
|
|
1300
|
+
disableOmpOAuthCredential(credential);
|
|
1301
|
+
return;
|
|
1093
1302
|
default:
|
|
1094
1303
|
throw new Error(`Unsupported OAuth tool: ${tool}`);
|
|
1095
1304
|
}
|
|
@@ -1105,6 +1314,8 @@ function applyOAuthCredential(tool, credential) {
|
|
|
1105
1314
|
return applyGeminiOAuth(credential);
|
|
1106
1315
|
case 'opencode':
|
|
1107
1316
|
return applyOpenCodeOAuth(credential);
|
|
1317
|
+
case 'omp':
|
|
1318
|
+
return applyOmpOAuth(credential);
|
|
1108
1319
|
default:
|
|
1109
1320
|
throw new Error(`Unsupported OAuth tool: ${tool}`);
|
|
1110
1321
|
}
|
|
@@ -72,6 +72,10 @@ function createRemoteMutationGuard(options = {}) {
|
|
|
72
72
|
};
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
function isRemoteMutationAllowedByEnv(env = process.env) {
|
|
76
|
+
return String(env.CC_TOOL_ALLOW_REMOTE_WRITE || '').toLowerCase() !== 'false';
|
|
77
|
+
}
|
|
78
|
+
|
|
75
79
|
function createRemoteRouteGuard(options = {}) {
|
|
76
80
|
const enabled = options.enabled === true;
|
|
77
81
|
const allowRemoteAccess = options.allowRemoteAccess === true;
|
|
@@ -113,6 +117,7 @@ module.exports = {
|
|
|
113
117
|
isLoopbackRequest,
|
|
114
118
|
isSameOriginRequest,
|
|
115
119
|
createRemoteMutationGuard,
|
|
120
|
+
isRemoteMutationAllowedByEnv,
|
|
116
121
|
createRemoteRouteGuard,
|
|
117
122
|
createSameOriginGuard
|
|
118
123
|
};
|
|
@@ -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,
|