coding-tool-x 3.7.1 → 3.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/web/assets/{Analytics-Dpje9L84.js → Analytics-BqDjJUJl.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-Cz6kasek.js → ConfigTemplates-DV2KFuC4.js} +1 -1
- package/dist/web/assets/{Home-BwTaYu3q.js → Home-D7hovkk9.js} +1 -1
- package/dist/web/assets/{PluginManager-DsN-xNXx.js → PluginManager-Bd3hhc5A.js} +1 -1
- package/dist/web/assets/{ProjectList-4BCObimU.js → ProjectList-BB4Whns8.js} +1 -1
- package/dist/web/assets/{SessionList-D4c8FRzq.js → SessionList-CvurKSRK.js} +1 -1
- package/dist/web/assets/{SkillManager-C-KYbXB5.js → SkillManager-DQjRXOFg.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-B-BlPJHX.js → WorkspaceManager-CZeXnxu1.js} +1 -1
- package/dist/web/assets/{icons-Dop5j7Bf.js → icons-nGdSKQn2.js} +1 -1
- package/dist/web/assets/index-BovYCFsd.js +2 -0
- package/dist/web/assets/index-kQCC5dlu.css +1 -0
- package/dist/web/index.html +3 -3
- package/package.json +1 -1
- package/src/commands/ui.js +1 -0
- package/src/index.js +3 -2
- package/src/server/api/channels.js +14 -1
- package/src/server/api/codex-channels.js +21 -1
- package/src/server/api/gemini-channels.js +21 -1
- package/src/server/api/oauth-credentials.js +15 -2
- package/src/server/api/omp-channels.js +117 -39
- package/src/server/api/opencode-channels.js +21 -1
- package/src/server/index.js +13 -5
- package/src/server/services/channel-sync-utils.js +368 -0
- package/src/server/services/channels.js +119 -0
- package/src/server/services/codex-channels.js +125 -0
- package/src/server/services/gemini-channels.js +123 -0
- 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/oauth-credentials-service.js +110 -3
- package/src/server/services/omp-channels.js +304 -2
- package/src/server/services/omp-settings-manager.js +2 -0
- package/src/server/services/opencode-channels.js +172 -4
- package/dist/web/assets/index-Btfvh0GG.js +0 -2
- package/dist/web/assets/index-CLNa6DhH.css +0 -1
|
@@ -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
|
};
|
|
@@ -240,6 +240,70 @@ function parseOpenCodeImport(rawText) {
|
|
|
240
240
|
};
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
+
function pickOmpCredentialEntry(parsed) {
|
|
244
|
+
if (Array.isArray(parsed)) {
|
|
245
|
+
return parsed.find(item => item && typeof item === 'object') || null;
|
|
246
|
+
}
|
|
247
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
if (parsed.provider || parsed.providerId || parsed.provider_id || parsed.providerKey || parsed.credential_type || parsed.data) {
|
|
251
|
+
return parsed;
|
|
252
|
+
}
|
|
253
|
+
const entry = Object.entries(parsed).find(([, value]) => value && typeof value === 'object');
|
|
254
|
+
return entry ? { provider: entry[0], ...entry[1] } : parsed;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function parseOmpImport(rawText) {
|
|
258
|
+
const parsed = tryParseJson(rawText);
|
|
259
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
260
|
+
throw new Error('OMP OAuth 仅支持 JSON 导入。');
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const entry = pickOmpCredentialEntry(parsed);
|
|
264
|
+
if (!entry || typeof entry !== 'object') {
|
|
265
|
+
throw new Error('OMP OAuth 导入缺少 provider。');
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const data = entry.data && typeof entry.data === 'object' ? entry.data : entry;
|
|
269
|
+
const providerId = safeString(
|
|
270
|
+
entry.providerId
|
|
271
|
+
|| entry.provider_id
|
|
272
|
+
|| entry.providerKey
|
|
273
|
+
|| entry.provider
|
|
274
|
+
|| data.providerId
|
|
275
|
+
|| data.provider
|
|
276
|
+
);
|
|
277
|
+
if (!providerId) {
|
|
278
|
+
throw new Error('OMP OAuth 导入缺少 providerId。');
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const accessToken = safeString(
|
|
282
|
+
data.accessToken
|
|
283
|
+
|| data.access_token
|
|
284
|
+
|| data.access
|
|
285
|
+
|| data.token
|
|
286
|
+
|| data.authToken
|
|
287
|
+
);
|
|
288
|
+
const credentialType = safeString(entry.credentialType || entry.credential_type || data.type || 'oauth') || 'oauth';
|
|
289
|
+
if (credentialType === 'oauth' && !accessToken && !entry.data) {
|
|
290
|
+
throw new Error('OMP OAuth 导入缺少 access/accessToken。');
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
providerId,
|
|
295
|
+
credentialType,
|
|
296
|
+
accessToken,
|
|
297
|
+
refreshToken: safeString(data.refreshToken || data.refresh_token || data.refresh),
|
|
298
|
+
expiresAt: safeNumber(data.expiresAt || data.expiry_date || data.expiryDate || data.expires),
|
|
299
|
+
accountId: safeString(data.accountId || data.account_id || entry.accountId || entry.account_id),
|
|
300
|
+
accountEmail: safeString(data.accountEmail || data.email || entry.accountEmail || entry.email),
|
|
301
|
+
identityKey: safeString(entry.identityKey || entry.identity_key || data.identityKey || data.identity_key),
|
|
302
|
+
importPayload: parsed,
|
|
303
|
+
primaryToken: accessToken
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
243
307
|
function parseCredentialInput(tool, rawText) {
|
|
244
308
|
switch (tool) {
|
|
245
309
|
case 'claude':
|
|
@@ -250,6 +314,8 @@ function parseCredentialInput(tool, rawText) {
|
|
|
250
314
|
return parseGeminiImport(rawText);
|
|
251
315
|
case 'opencode':
|
|
252
316
|
return parseOpenCodeImport(rawText);
|
|
317
|
+
case 'omp':
|
|
318
|
+
return parseOmpImport(rawText);
|
|
253
319
|
default:
|
|
254
320
|
throw new Error(`Unsupported OAuth tool: ${tool}`);
|
|
255
321
|
}
|
|
@@ -261,7 +327,7 @@ function buildCredentialName(tool, metadata, providedName = '') {
|
|
|
261
327
|
return explicit;
|
|
262
328
|
}
|
|
263
329
|
|
|
264
|
-
if (tool === 'opencode' && safeString(metadata.providerId)) {
|
|
330
|
+
if ((tool === 'opencode' || tool === 'omp') && safeString(metadata.providerId)) {
|
|
265
331
|
const accountLabel = safeString(metadata.accountId || metadata.accountEmail);
|
|
266
332
|
return accountLabel
|
|
267
333
|
? `${tool} - ${metadata.providerId} - ${accountLabel}`
|
|
@@ -386,6 +452,19 @@ function extractSecrets(tool, metadata) {
|
|
|
386
452
|
enterpriseUrl: metadata.enterpriseUrl || '',
|
|
387
453
|
primaryToken: metadata.primaryToken || metadata.accessToken || ''
|
|
388
454
|
};
|
|
455
|
+
case 'omp':
|
|
456
|
+
return {
|
|
457
|
+
providerId: metadata.providerId || '',
|
|
458
|
+
credentialType: metadata.credentialType || 'oauth',
|
|
459
|
+
accessToken: metadata.accessToken || '',
|
|
460
|
+
refreshToken: metadata.refreshToken || '',
|
|
461
|
+
expiresAt: metadata.expiresAt || null,
|
|
462
|
+
accountId: metadata.accountId || '',
|
|
463
|
+
accountEmail: metadata.accountEmail || '',
|
|
464
|
+
identityKey: metadata.identityKey || '',
|
|
465
|
+
importPayload: metadata.importPayload || null,
|
|
466
|
+
primaryToken: metadata.primaryToken || metadata.accessToken || ''
|
|
467
|
+
};
|
|
389
468
|
default:
|
|
390
469
|
return { primaryToken: metadata.primaryToken || metadata.accessToken || '' };
|
|
391
470
|
}
|
|
@@ -395,7 +474,7 @@ function stableFingerprintValue(tool, metadata) {
|
|
|
395
474
|
// 优先使用稳定标识符,避免 access token 轮换导致重复记录
|
|
396
475
|
const stableId = metadata.accountEmail
|
|
397
476
|
|| metadata.accountId
|
|
398
|
-
|| (tool === 'opencode' ? metadata.providerId : '')
|
|
477
|
+
|| ((tool === 'opencode' || tool === 'omp') ? metadata.providerId : '')
|
|
399
478
|
|| metadata.refreshToken
|
|
400
479
|
|| metadata.primaryToken
|
|
401
480
|
|| metadata.accessToken
|
|
@@ -559,6 +638,11 @@ function cleanupManagedArtifacts(tool) {
|
|
|
559
638
|
|
|
560
639
|
if (tool === 'opencode') {
|
|
561
640
|
opencodeSettingsManager.deleteBackup?.();
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
if (tool === 'omp') {
|
|
645
|
+
return;
|
|
562
646
|
}
|
|
563
647
|
}
|
|
564
648
|
|
|
@@ -597,6 +681,14 @@ async function stopProxyIfRunning(tool) {
|
|
|
597
681
|
}
|
|
598
682
|
return false;
|
|
599
683
|
}
|
|
684
|
+
case 'omp': {
|
|
685
|
+
const { stopOmpProxyServer, getOmpProxyStatus } = require('../omp-proxy-server');
|
|
686
|
+
if (getOmpProxyStatus().running) {
|
|
687
|
+
await stopOmpProxyServer();
|
|
688
|
+
return true;
|
|
689
|
+
}
|
|
690
|
+
return false;
|
|
691
|
+
}
|
|
600
692
|
default:
|
|
601
693
|
throw new Error(`Unsupported OAuth tool: ${tool}`);
|
|
602
694
|
}
|
|
@@ -625,6 +717,11 @@ function disableAllChannelsForTool(tool) {
|
|
|
625
717
|
disableAllChannels();
|
|
626
718
|
break;
|
|
627
719
|
}
|
|
720
|
+
case 'omp': {
|
|
721
|
+
const { disableAllChannels } = require('./omp-channels');
|
|
722
|
+
disableAllChannels();
|
|
723
|
+
break;
|
|
724
|
+
}
|
|
628
725
|
}
|
|
629
726
|
} catch (err) {
|
|
630
727
|
console.warn(`[OAuth] Failed to disable channels for ${tool}:`, err.message);
|
|
@@ -635,7 +732,7 @@ async function applyStoredCredential(tool, credentialId) {
|
|
|
635
732
|
const entry = findStoredCredential(tool, credentialId);
|
|
636
733
|
const proxyStopped = await stopProxyIfRunning(tool);
|
|
637
734
|
cleanupManagedArtifacts(tool);
|
|
638
|
-
if (tool !== 'opencode') {
|
|
735
|
+
if (tool !== 'opencode' && tool !== 'omp') {
|
|
639
736
|
disableAllChannelsForTool(tool);
|
|
640
737
|
}
|
|
641
738
|
applyOAuthCredential(tool, entry.secrets);
|
|
@@ -818,6 +915,16 @@ async function fetchCredentialUsage(tool, credentialId) {
|
|
|
818
915
|
return await fetchCodexUsage(accessToken);
|
|
819
916
|
}
|
|
820
917
|
}
|
|
918
|
+
case 'omp': {
|
|
919
|
+
const providerId = entry.providerId || secrets.providerId || '';
|
|
920
|
+
if (providerId.includes('claude') || providerId.includes('anthropic')) {
|
|
921
|
+
return await fetchClaudeUsage(accessToken);
|
|
922
|
+
} else if (providerId.includes('gemini') || providerId.includes('google')) {
|
|
923
|
+
return await fetchGeminiUsage(accessToken);
|
|
924
|
+
} else {
|
|
925
|
+
return await fetchCodexUsage(accessToken);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
821
928
|
default:
|
|
822
929
|
return { error: `不支持的工具: ${tool}` };
|
|
823
930
|
}
|