coding-tool-x 3.4.4 → 3.4.5
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/dist/web/assets/{Analytics-_Byi9M6y.js → Analytics-DFWyPf5C.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-DIwosdtG.js → ConfigTemplates-BFE7hmKd.js} +1 -1
- package/dist/web/assets/{Home-DdNMuQ9c.js → Home-DZUuCrxk.js} +1 -1
- package/dist/web/assets/{PluginManager-iuY24cnW.js → PluginManager-WyGY2BQN.js} +1 -1
- package/dist/web/assets/{ProjectList-DSkMulzL.js → ProjectList-CBc0QawN.js} +1 -1
- package/dist/web/assets/{SessionList-B6pGquIr.js → SessionList-CdPR7QLq.js} +1 -1
- package/dist/web/assets/{SkillManager-CHtQX5r8.js → SkillManager-B5-DxQOS.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-gNPs-VaI.js → WorkspaceManager-C7yqFjpi.js} +1 -1
- package/dist/web/assets/index-BDsmoSfO.js +2 -0
- package/dist/web/assets/{index-pMqqe9ei.css → index-C1pzEgmj.css} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +2 -2
- package/src/server/api/claude-hooks.js +1 -0
- package/src/server/api/plugins.js +161 -14
- package/src/server/api/skills.js +62 -7
- package/src/server/codex-proxy-server.js +10 -2
- package/src/server/gemini-proxy-server.js +10 -2
- package/src/server/opencode-proxy-server.js +10 -2
- package/src/server/proxy-server.js +10 -2
- package/src/server/services/codex-channels.js +64 -21
- package/src/server/services/codex-env-manager.js +44 -28
- package/src/server/services/plugins-service.js +1060 -235
- package/src/server/services/proxy-runtime.js +129 -5
- package/src/server/services/server-shutdown.js +79 -0
- package/src/server/services/skill-service.js +142 -17
- package/dist/web/assets/index-DGjGCo37.js +0 -2
|
@@ -5,27 +5,46 @@ const toml = require('toml');
|
|
|
5
5
|
const tomlStringify = require('@iarna/toml').stringify;
|
|
6
6
|
const { PATHS } = require('../../config/paths');
|
|
7
7
|
const { getCodexDir } = require('./codex-config');
|
|
8
|
-
const { isProxyConfig } = require('./codex-settings-manager');
|
|
8
|
+
const { isProxyConfig, readConfig } = require('./codex-settings-manager');
|
|
9
9
|
const { clearNativeOAuth } = require('./native-oauth-adapters');
|
|
10
10
|
const { syncCodexUserEnvironment } = require('./codex-env-manager');
|
|
11
11
|
const BaseChannelService = require('./base/base-channel-service');
|
|
12
12
|
|
|
13
|
-
const
|
|
13
|
+
const CODEX_MANAGED_ENV_KEY = 'CC_PROXY_KEY';
|
|
14
14
|
const CODEX_PROXY_ENV_VALUE = 'PROXY_KEY';
|
|
15
15
|
|
|
16
16
|
// ── Codex 特有工具函数 ──
|
|
17
17
|
|
|
18
|
-
function
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
function resolveCurrentManagedChannel(channels = []) {
|
|
19
|
+
const allChannels = Array.isArray(channels) ? channels : [];
|
|
20
|
+
let currentProvider = '';
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
currentProvider = String(readConfig()?.model_provider || '').trim();
|
|
24
|
+
} catch (err) {
|
|
25
|
+
currentProvider = '';
|
|
21
26
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
|
|
28
|
+
if (currentProvider && currentProvider !== 'cc-proxy') {
|
|
29
|
+
const matched = allChannels.find(ch => ch.providerKey === currentProvider);
|
|
30
|
+
if (matched) {
|
|
31
|
+
return matched;
|
|
26
32
|
}
|
|
27
33
|
}
|
|
28
|
-
|
|
34
|
+
|
|
35
|
+
return allChannels.find(ch => ch.enabled !== false) || null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function buildManagedCodexEnvMap(channels = [], { includeProxyKey = false, activeChannel = null } = {}) {
|
|
39
|
+
if (includeProxyKey) {
|
|
40
|
+
return { [CODEX_MANAGED_ENV_KEY]: CODEX_PROXY_ENV_VALUE };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const targetChannel = activeChannel || resolveCurrentManagedChannel(channels);
|
|
44
|
+
if (targetChannel?.apiKey) {
|
|
45
|
+
return { [CODEX_MANAGED_ENV_KEY]: targetChannel.apiKey };
|
|
46
|
+
}
|
|
47
|
+
return {};
|
|
29
48
|
}
|
|
30
49
|
|
|
31
50
|
function syncAllChannelEnvVars() {
|
|
@@ -34,7 +53,8 @@ function syncAllChannelEnvVars() {
|
|
|
34
53
|
const data = svc.loadChannels();
|
|
35
54
|
const proxyRunning = isProxyConfig();
|
|
36
55
|
const envMap = buildManagedCodexEnvMap(data.channels, {
|
|
37
|
-
includeProxyKey: proxyRunning
|
|
56
|
+
includeProxyKey: proxyRunning,
|
|
57
|
+
activeChannel: proxyRunning ? null : resolveCurrentManagedChannel(data.channels)
|
|
38
58
|
});
|
|
39
59
|
syncCodexUserEnvironment(envMap, { replace: true });
|
|
40
60
|
} catch (err) {
|
|
@@ -87,7 +107,7 @@ function writeCodexConfigForMultiChannel(channels) {
|
|
|
87
107
|
name: ch.name,
|
|
88
108
|
base_url: ch.baseUrl,
|
|
89
109
|
wire_api: ch.wireApi || 'responses',
|
|
90
|
-
env_key:
|
|
110
|
+
env_key: CODEX_MANAGED_ENV_KEY,
|
|
91
111
|
requires_openai_auth: ch.requiresOpenaiAuth !== false
|
|
92
112
|
};
|
|
93
113
|
if (ch.queryParams && Object.keys(ch.queryParams).length > 0) {
|
|
@@ -121,7 +141,7 @@ class CodexChannelService extends BaseChannelService {
|
|
|
121
141
|
_applyDefaults(channel) {
|
|
122
142
|
const ch = super._applyDefaults(channel);
|
|
123
143
|
ch.providerKey = ch.providerKey || '';
|
|
124
|
-
ch.envKey =
|
|
144
|
+
ch.envKey = CODEX_MANAGED_ENV_KEY;
|
|
125
145
|
ch.wireApi = ch.wireApi || 'responses';
|
|
126
146
|
ch.model = ch.model || '';
|
|
127
147
|
ch.speedTestModel = ch.speedTestModel || null;
|
|
@@ -143,19 +163,38 @@ class CodexChannelService extends BaseChannelService {
|
|
|
143
163
|
}
|
|
144
164
|
|
|
145
165
|
_onAfterCreate(_channel, _allChannels) {
|
|
166
|
+
if (_channel.enabled !== false && !isProxyConfig()) {
|
|
167
|
+
this._applyToNativeSettings(_channel);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
146
170
|
syncAllChannelEnvVars();
|
|
147
|
-
// 注意:不再自动写入 config.toml,只在开启代理控制时才同步
|
|
148
171
|
}
|
|
149
172
|
|
|
150
|
-
_onAfterUpdate(_old, _next,
|
|
173
|
+
_onAfterUpdate(_old, _next, allChannels) {
|
|
174
|
+
if (!isProxyConfig()) {
|
|
175
|
+
if (_old.enabled === false && _next.enabled !== false) {
|
|
176
|
+
this._applyToNativeSettings(_next);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const activeChannel = resolveCurrentManagedChannel(allChannels);
|
|
180
|
+
if (_next.enabled !== false && activeChannel?.id === _next.id) {
|
|
181
|
+
this._applyToNativeSettings(_next);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
151
185
|
syncAllChannelEnvVars();
|
|
152
|
-
// 注意:不再自动写入 config.toml,只在开启代理控制时才同步
|
|
153
186
|
}
|
|
154
187
|
|
|
155
|
-
_onAfterDelete(_channel,
|
|
188
|
+
_onAfterDelete(_channel, allChannels) {
|
|
189
|
+
if (!isProxyConfig()) {
|
|
190
|
+
const activeChannel = resolveCurrentManagedChannel(allChannels);
|
|
191
|
+
if (activeChannel && activeChannel.enabled !== false) {
|
|
192
|
+
this._applyToNativeSettings(activeChannel);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
156
196
|
clearNativeOAuth('codex');
|
|
157
197
|
syncAllChannelEnvVars();
|
|
158
|
-
// 注意:不再自动写入 config.toml,只在开启代理控制时才同步
|
|
159
198
|
}
|
|
160
199
|
|
|
161
200
|
_applyToNativeSettings(channel) {
|
|
@@ -184,7 +223,7 @@ class CodexChannelService extends BaseChannelService {
|
|
|
184
223
|
name: channel.name,
|
|
185
224
|
base_url: channel.baseUrl,
|
|
186
225
|
wire_api: channel.wireApi || 'responses',
|
|
187
|
-
env_key:
|
|
226
|
+
env_key: CODEX_MANAGED_ENV_KEY,
|
|
188
227
|
requires_openai_auth: channel.requiresOpenaiAuth !== false
|
|
189
228
|
};
|
|
190
229
|
|
|
@@ -215,10 +254,9 @@ const service = getServiceInstance();
|
|
|
215
254
|
function getChannels() { return service.getChannels(); }
|
|
216
255
|
function getEnabledChannels() { return service.getEnabledChannels(); }
|
|
217
256
|
function createChannel(name, providerKey, baseUrl, apiKey, wireApi, extraConfig = {}) {
|
|
218
|
-
const envKey = extraConfig.envKey || `${providerKey.toUpperCase()}_API_KEY`;
|
|
219
257
|
return service.createChannel({
|
|
220
258
|
name, providerKey, baseUrl, apiKey, wireApi,
|
|
221
|
-
envKey,
|
|
259
|
+
envKey: CODEX_MANAGED_ENV_KEY,
|
|
222
260
|
...extraConfig,
|
|
223
261
|
});
|
|
224
262
|
}
|
|
@@ -251,4 +289,9 @@ module.exports = {
|
|
|
251
289
|
applyChannelToSettings,
|
|
252
290
|
getEffectiveApiKey,
|
|
253
291
|
disableAllChannels,
|
|
292
|
+
_test: {
|
|
293
|
+
buildManagedCodexEnvMap,
|
|
294
|
+
CODEX_MANAGED_ENV_KEY,
|
|
295
|
+
resolveCurrentManagedChannel
|
|
296
|
+
}
|
|
254
297
|
};
|
|
@@ -32,6 +32,40 @@ function powershellQuote(value) {
|
|
|
32
32
|
return `'${String(value).replace(/'/g, "''")}'`;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
function buildWindowsSettingChangeScript() {
|
|
36
|
+
return [
|
|
37
|
+
'Add-Type -Namespace Win32 -Name NativeMethods -MemberDefinition @"',
|
|
38
|
+
'[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]',
|
|
39
|
+
'public static extern IntPtr SendMessageTimeout(',
|
|
40
|
+
' IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam,',
|
|
41
|
+
' uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);',
|
|
42
|
+
'"@',
|
|
43
|
+
'$HWND_BROADCAST = [IntPtr]0xffff',
|
|
44
|
+
'$WM_SETTINGCHANGE = 0x1a',
|
|
45
|
+
'$SMTO_ABORTIFHUNG = 0x0002',
|
|
46
|
+
'$result = [UIntPtr]::Zero',
|
|
47
|
+
'[Win32.NativeMethods]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE,',
|
|
48
|
+
' [UIntPtr]::Zero, "Environment", $SMTO_ABORTIFHUNG, 5000, [ref]$result) | Out-Null'
|
|
49
|
+
].join('\n');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function buildWindowsEnvBatchScript(operations = [], { includeSettingChangeBroadcast = true } = {}) {
|
|
53
|
+
const normalizedOperations = Array.isArray(operations) ? operations.filter(Boolean) : [];
|
|
54
|
+
const lines = normalizedOperations.map((operation) => {
|
|
55
|
+
const key = powershellQuote(operation.key || '');
|
|
56
|
+
if (operation.remove) {
|
|
57
|
+
return `[Environment]::SetEnvironmentVariable(${key}, $null, 'User')`;
|
|
58
|
+
}
|
|
59
|
+
return `[Environment]::SetEnvironmentVariable(${key}, ${powershellQuote(operation.value || '')}, 'User')`;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if (includeSettingChangeBroadcast && lines.length > 0) {
|
|
63
|
+
lines.push(buildWindowsSettingChangeScript());
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return lines.join('\n');
|
|
67
|
+
}
|
|
68
|
+
|
|
35
69
|
function buildHomeRelativeShellPath(filePath, homeDir) {
|
|
36
70
|
const normalizedHome = path.resolve(homeDir);
|
|
37
71
|
const normalizedFilePath = path.resolve(filePath);
|
|
@@ -341,48 +375,28 @@ function runLaunchctlCommand(args, execSync) {
|
|
|
341
375
|
}
|
|
342
376
|
|
|
343
377
|
function broadcastWindowsSettingChange(execSync) {
|
|
344
|
-
|
|
345
|
-
'Add-Type -Namespace Win32 -Name NativeMethods -MemberDefinition @"',
|
|
346
|
-
'[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]',
|
|
347
|
-
'public static extern IntPtr SendMessageTimeout(',
|
|
348
|
-
' IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam,',
|
|
349
|
-
' uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);',
|
|
350
|
-
'"@',
|
|
351
|
-
'$HWND_BROADCAST = [IntPtr]0xffff',
|
|
352
|
-
'$WM_SETTINGCHANGE = 0x1a',
|
|
353
|
-
'$SMTO_ABORTIFHUNG = 0x0002',
|
|
354
|
-
'$result = [UIntPtr]::Zero',
|
|
355
|
-
'[Win32.NativeMethods]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE,',
|
|
356
|
-
' [UIntPtr]::Zero, "Environment", $SMTO_ABORTIFHUNG, 5000, [ref]$result) | Out-Null'
|
|
357
|
-
].join('\n');
|
|
358
|
-
runWindowsEnvCommand(script, execSync);
|
|
378
|
+
runWindowsEnvCommand(buildWindowsSettingChangeScript(), execSync);
|
|
359
379
|
}
|
|
360
380
|
|
|
361
381
|
function syncWindowsEnvironment(nextValues, previousState, options) {
|
|
362
382
|
const { stateFilePath, execSync } = options;
|
|
363
383
|
const nextKeys = Object.keys(nextValues).sort();
|
|
364
384
|
const previousValues = previousState.values || {};
|
|
365
|
-
|
|
385
|
+
const operations = [];
|
|
366
386
|
|
|
367
387
|
for (const [key, value] of Object.entries(nextValues)) {
|
|
368
388
|
if (previousValues[key] === value) continue;
|
|
369
|
-
|
|
370
|
-
changed = true;
|
|
389
|
+
operations.push({ key, value });
|
|
371
390
|
}
|
|
372
391
|
|
|
373
392
|
for (const key of Object.keys(previousValues)) {
|
|
374
393
|
if (Object.prototype.hasOwnProperty.call(nextValues, key)) continue;
|
|
375
|
-
|
|
376
|
-
changed = true;
|
|
394
|
+
operations.push({ key, remove: true });
|
|
377
395
|
}
|
|
378
396
|
|
|
379
|
-
|
|
397
|
+
const changed = operations.length > 0;
|
|
380
398
|
if (changed) {
|
|
381
|
-
|
|
382
|
-
broadcastWindowsSettingChange(execSync);
|
|
383
|
-
} catch {
|
|
384
|
-
// 广播失败不影响主流程,环境变量已写入注册表
|
|
385
|
-
}
|
|
399
|
+
runWindowsEnvCommand(buildWindowsEnvBatchScript(operations), execSync);
|
|
386
400
|
}
|
|
387
401
|
|
|
388
402
|
if (nextKeys.length > 0) {
|
|
@@ -427,14 +441,14 @@ function runWindowsEnvCommand(script, execSync) {
|
|
|
427
441
|
|
|
428
442
|
function setWindowsUserEnv(key, value, execSync) {
|
|
429
443
|
runWindowsEnvCommand(
|
|
430
|
-
|
|
444
|
+
buildWindowsEnvBatchScript([{ key, value }], { includeSettingChangeBroadcast: false }),
|
|
431
445
|
execSync
|
|
432
446
|
);
|
|
433
447
|
}
|
|
434
448
|
|
|
435
449
|
function removeWindowsUserEnv(key, execSync) {
|
|
436
450
|
runWindowsEnvCommand(
|
|
437
|
-
|
|
451
|
+
buildWindowsEnvBatchScript([{ key, remove: true }], { includeSettingChangeBroadcast: false }),
|
|
438
452
|
execSync
|
|
439
453
|
);
|
|
440
454
|
}
|
|
@@ -473,8 +487,10 @@ module.exports = {
|
|
|
473
487
|
syncCodexUserEnvironment,
|
|
474
488
|
_test: {
|
|
475
489
|
broadcastWindowsSettingChange,
|
|
490
|
+
buildWindowsEnvBatchScript,
|
|
476
491
|
buildHomeRelativeShellPath,
|
|
477
492
|
buildNextEnvValues,
|
|
493
|
+
buildWindowsSettingChangeScript,
|
|
478
494
|
buildSourceSnippet,
|
|
479
495
|
getPosixProfileCandidates,
|
|
480
496
|
readState,
|