coding-tool-x 3.4.9 → 3.4.10
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/package.json
CHANGED
|
@@ -101,7 +101,7 @@ function generateSystemNotificationCommand(type, platformOverride = platform) {
|
|
|
101
101
|
} else if (platformOverride === 'win32') {
|
|
102
102
|
// Windows
|
|
103
103
|
if (type === 'dialog') {
|
|
104
|
-
return `powershell -
|
|
104
|
+
return `powershell -Command "Add-Type -AssemblyName PresentationFramework; [System.Windows.MessageBox]::Show('Claude Code 任务已完成 | 等待交互', 'Coding Tool', 'OK', 'Information')" || ${buildWindowsPopupCommand()}`;
|
|
105
105
|
} else {
|
|
106
106
|
return buildWindowsPopupCommand();
|
|
107
107
|
}
|
package/src/server/api/proxy.js
CHANGED
|
@@ -11,7 +11,7 @@ const {
|
|
|
11
11
|
hasBackup,
|
|
12
12
|
readSettings
|
|
13
13
|
} = require('../services/settings-manager');
|
|
14
|
-
const { getAllChannels } = require('../services/channels');
|
|
14
|
+
const { getAllChannels, extractApiKeyFromHelper } = require('../services/channels');
|
|
15
15
|
const { clearNativeOAuth } = require('../services/native-oauth-adapters');
|
|
16
16
|
const { clearAllLogs } = require('../websocket-server');
|
|
17
17
|
const { PATHS, NATIVE_PATHS, ensureStorageDirMigrated } = require('../../config/paths');
|
|
@@ -101,10 +101,7 @@ function findActiveChannelFromSettings() {
|
|
|
101
101
|
|
|
102
102
|
// 如果 apiKey 仍为空,尝试从 apiKeyHelper 提取
|
|
103
103
|
if (!apiKey && settings?.apiKeyHelper) {
|
|
104
|
-
|
|
105
|
-
if (match && match[1]) {
|
|
106
|
-
apiKey = match[1];
|
|
107
|
-
}
|
|
104
|
+
apiKey = extractApiKeyFromHelper(settings.apiKeyHelper);
|
|
108
105
|
}
|
|
109
106
|
|
|
110
107
|
const channels = getAllChannels();
|
|
@@ -44,18 +44,22 @@ function extractApiKeyFromHelper(apiKeyHelper) {
|
|
|
44
44
|
return '';
|
|
45
45
|
}
|
|
46
46
|
const helper = apiKeyHelper.trim();
|
|
47
|
-
let match = helper.match(/^echo\s+["']([^"']+)["']$/);
|
|
47
|
+
let match = helper.match(/^echo\s+["']([^"']+)["']$/i);
|
|
48
48
|
if (match && match[1]) return match[1];
|
|
49
|
-
match = helper.match(/^
|
|
49
|
+
match = helper.match(/^echo\s+([^\s].*)$/i);
|
|
50
|
+
if (match && match[1]) return match[1].trim();
|
|
51
|
+
match = helper.match(/^cmd(?:\.exe)?\s*\/c\s+echo\s+([^\s].*)$/i);
|
|
52
|
+
if (match && match[1]) return match[1].trim();
|
|
53
|
+
match = helper.match(/^printf\s+["'][^"']*["']\s+["']([^"']+)["']$/i);
|
|
50
54
|
if (match && match[1]) return match[1];
|
|
51
55
|
return '';
|
|
52
56
|
}
|
|
53
57
|
|
|
54
|
-
function buildApiKeyHelperCommand() {
|
|
58
|
+
function buildApiKeyHelperCommand(value) {
|
|
55
59
|
if (isWindowsLikePlatform(process.platform, process.env)) {
|
|
56
|
-
return
|
|
60
|
+
return `cmd /c echo ${value}`;
|
|
57
61
|
}
|
|
58
|
-
return
|
|
62
|
+
return `echo '${value}'`;
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
// ── Claude 原生设置写入 ──
|
|
@@ -114,7 +118,7 @@ function updateClaudeSettingsWithModelConfig(channel) {
|
|
|
114
118
|
delete settings.env;
|
|
115
119
|
}
|
|
116
120
|
|
|
117
|
-
settings.apiKeyHelper = buildApiKeyHelperCommand();
|
|
121
|
+
settings.apiKeyHelper = buildApiKeyHelperCommand(apiKey);
|
|
118
122
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
|
|
119
123
|
}
|
|
120
124
|
|
|
@@ -147,7 +151,7 @@ function updateClaudeSettings(baseUrl, apiKey) {
|
|
|
147
151
|
delete settings.env;
|
|
148
152
|
}
|
|
149
153
|
|
|
150
|
-
settings.apiKeyHelper = buildApiKeyHelperCommand();
|
|
154
|
+
settings.apiKeyHelper = buildApiKeyHelperCommand(apiKey);
|
|
151
155
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
|
|
152
156
|
}
|
|
153
157
|
|
|
@@ -326,4 +330,5 @@ module.exports = {
|
|
|
326
330
|
updateClaudeSettingsWithModelConfig,
|
|
327
331
|
getEffectiveApiKey,
|
|
328
332
|
disableAllChannels,
|
|
333
|
+
extractApiKeyFromHelper,
|
|
329
334
|
};
|
|
@@ -5,6 +5,9 @@ const { PATHS, HOME_DIR } = require('../../config/paths');
|
|
|
5
5
|
|
|
6
6
|
const PROFILE_MARKER_START = '# >>> coding-tool codex env >>>';
|
|
7
7
|
const PROFILE_MARKER_END = '# <<< coding-tool codex env <<<';
|
|
8
|
+
const WINDOWS_ENV_COMMAND_TIMEOUT_MS = 15000;
|
|
9
|
+
const WINDOWS_SETTING_CHANGE_TIMEOUT_MS = 1000;
|
|
10
|
+
const WINDOWS_SETTING_CHANGE_COMMAND_TIMEOUT_MS = 7000;
|
|
8
11
|
|
|
9
12
|
function defaultEnvFilePath(configDir) {
|
|
10
13
|
return path.join(configDir, 'codex-env.sh');
|
|
@@ -32,7 +35,7 @@ function powershellQuote(value) {
|
|
|
32
35
|
return `'${String(value).replace(/'/g, "''")}'`;
|
|
33
36
|
}
|
|
34
37
|
|
|
35
|
-
function buildWindowsSettingChangeScript() {
|
|
38
|
+
function buildWindowsSettingChangeScript(timeoutMs = WINDOWS_SETTING_CHANGE_TIMEOUT_MS) {
|
|
36
39
|
return [
|
|
37
40
|
'Add-Type -Namespace Win32 -Name NativeMethods -MemberDefinition @"',
|
|
38
41
|
'[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]',
|
|
@@ -45,11 +48,11 @@ function buildWindowsSettingChangeScript() {
|
|
|
45
48
|
'$SMTO_ABORTIFHUNG = 0x0002',
|
|
46
49
|
'$result = [UIntPtr]::Zero',
|
|
47
50
|
'[Win32.NativeMethods]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE,',
|
|
48
|
-
|
|
51
|
+
` [UIntPtr]::Zero, "Environment", $SMTO_ABORTIFHUNG, ${timeoutMs}, [ref]$result) | Out-Null`
|
|
49
52
|
].join('\n');
|
|
50
53
|
}
|
|
51
54
|
|
|
52
|
-
function buildWindowsEnvBatchScript(operations = [], { includeSettingChangeBroadcast =
|
|
55
|
+
function buildWindowsEnvBatchScript(operations = [], { includeSettingChangeBroadcast = true } = {}) {
|
|
53
56
|
const normalizedOperations = Array.isArray(operations) ? operations.filter(Boolean) : [];
|
|
54
57
|
const lines = normalizedOperations.map((operation) => {
|
|
55
58
|
const key = powershellQuote(operation.key || '');
|
|
@@ -375,7 +378,12 @@ function runLaunchctlCommand(args, execSync) {
|
|
|
375
378
|
}
|
|
376
379
|
|
|
377
380
|
function broadcastWindowsSettingChange(execSync) {
|
|
378
|
-
|
|
381
|
+
// WM_SETTINGCHANGE 只是帮助已运行的 GUI/终端尽快感知环境变化。
|
|
382
|
+
// 用户级环境变量已经写入注册表,即使这里超时,新开进程仍然能读到。
|
|
383
|
+
runWindowsEnvCommand(buildWindowsSettingChangeScript(), execSync, {
|
|
384
|
+
timeout: WINDOWS_SETTING_CHANGE_COMMAND_TIMEOUT_MS,
|
|
385
|
+
ignoreErrors: true
|
|
386
|
+
});
|
|
379
387
|
}
|
|
380
388
|
|
|
381
389
|
function syncWindowsEnvironment(nextValues, previousState, options) {
|
|
@@ -398,14 +406,10 @@ function syncWindowsEnvironment(nextValues, previousState, options) {
|
|
|
398
406
|
if (changed) {
|
|
399
407
|
runWindowsEnvCommand(
|
|
400
408
|
buildWindowsEnvBatchScript(operations, { includeSettingChangeBroadcast: false }),
|
|
401
|
-
execSync
|
|
409
|
+
execSync,
|
|
410
|
+
{ timeout: WINDOWS_ENV_COMMAND_TIMEOUT_MS }
|
|
402
411
|
);
|
|
403
|
-
|
|
404
|
-
// WM_SETTINGCHANGE 只是帮助已打开的应用刷新环境变量,失败不应让主流程报错。
|
|
405
|
-
broadcastWindowsSettingChange(execSync);
|
|
406
|
-
} catch {
|
|
407
|
-
// ignore broadcast failures; registry writes are already durable
|
|
408
|
-
}
|
|
412
|
+
broadcastWindowsSettingChange(execSync);
|
|
409
413
|
}
|
|
410
414
|
|
|
411
415
|
if (nextKeys.length > 0) {
|
|
@@ -430,21 +434,28 @@ function syncWindowsEnvironment(nextValues, previousState, options) {
|
|
|
430
434
|
};
|
|
431
435
|
}
|
|
432
436
|
|
|
433
|
-
function runWindowsEnvCommand(script, execSync) {
|
|
437
|
+
function runWindowsEnvCommand(script, execSync, options = {}) {
|
|
438
|
+
const timeout = Number(options.timeout) > 0
|
|
439
|
+
? Number(options.timeout)
|
|
440
|
+
: WINDOWS_ENV_COMMAND_TIMEOUT_MS;
|
|
441
|
+
const ignoreErrors = options.ignoreErrors === true;
|
|
434
442
|
const candidates = ['powershell', 'pwsh'];
|
|
435
443
|
let lastError = null;
|
|
436
444
|
for (const command of candidates) {
|
|
437
445
|
try {
|
|
438
446
|
execSync(command, ['-NoProfile', '-NonInteractive', '-Command', script], {
|
|
439
447
|
stdio: ['ignore', 'ignore', 'ignore'],
|
|
440
|
-
timeout
|
|
448
|
+
timeout,
|
|
441
449
|
windowsHide: true
|
|
442
450
|
});
|
|
443
|
-
return;
|
|
451
|
+
return true;
|
|
444
452
|
} catch (error) {
|
|
445
453
|
lastError = error;
|
|
446
454
|
}
|
|
447
455
|
}
|
|
456
|
+
if (ignoreErrors) {
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
448
459
|
throw lastError || new Error('No PowerShell executable available');
|
|
449
460
|
}
|
|
450
461
|
|