@kikkimo/claude-launcher 2.0.0 → 2.1.0
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/CHANGELOG.md +91 -0
- package/README.md +9 -6
- package/claude-launcher +57 -3
- package/docs/README-zh.md +9 -6
- package/lib/auth/password-input.js +101 -87
- package/lib/i18n/locales/de.js +17 -2
- package/lib/i18n/locales/en.js +17 -2
- package/lib/i18n/locales/es.js +17 -2
- package/lib/i18n/locales/fr.js +18 -3
- package/lib/i18n/locales/it.js +16 -0
- package/lib/i18n/locales/ja.js +17 -2
- package/lib/i18n/locales/ko.js +17 -2
- package/lib/i18n/locales/pt.js +16 -0
- package/lib/i18n/locales/ru.js +16 -0
- package/lib/i18n/locales/zh-TW.js +17 -2
- package/lib/i18n/locales/zh.js +17 -2
- package/lib/launcher.js +153 -47
- package/lib/presets/providers.js +46 -2
- package/lib/ui/interactive-table.js +102 -24
- package/lib/ui/menu.js +213 -144
- package/lib/ui/prompts.js +116 -85
- package/lib/utils/stdin-manager.js +715 -0
- package/package.json +1 -1
package/lib/i18n/locales/it.js
CHANGED
|
@@ -335,11 +335,27 @@ module.exports = {
|
|
|
335
335
|
press_key_return: "Premi un tasto qualsiasi per tornare al menu principale...",
|
|
336
336
|
environment_variables: "Variabili d'ambiente:",
|
|
337
337
|
using_third_party_api: "Uso Configurazione API di Terze Parti",
|
|
338
|
+
provider_optimizations_applied: "Ottimizzazioni del fornitore applicate",
|
|
339
|
+
extended_timeout_format: "Timeout esteso: {0}s ({1} minuti)",
|
|
340
|
+
extended_timeout_format_singular: "Timeout esteso: {0}s ({1} minuto)",
|
|
341
|
+
non_essential_traffic_disabled: "Traffico non essenziale disabilitato",
|
|
342
|
+
custom_env_var: "{0}={1}",
|
|
343
|
+
// Deprecated - kept for backward compatibility
|
|
338
344
|
deepseek_optimizations: "Ottimizzazioni DeepSeek abilitate:",
|
|
339
345
|
extended_timeout: "Timeout esteso (600s)",
|
|
340
346
|
non_essential_disabled: "Traffico non essenziale disabilitato"
|
|
341
347
|
},
|
|
342
348
|
|
|
349
|
+
// Note del fornitore
|
|
350
|
+
provider: {
|
|
351
|
+
note_prefix: "Nota",
|
|
352
|
+
notes: {
|
|
353
|
+
deepseek: "Richiede timeout esteso per attività di ragionamento complesse",
|
|
354
|
+
zhipu: "Richiede timeout esteso per risposte grandi",
|
|
355
|
+
zai: "Richiede timeout esteso per risposte grandi"
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
|
|
343
359
|
// Additional UI messages
|
|
344
360
|
ui: {
|
|
345
361
|
general: {
|
package/lib/i18n/locales/ja.js
CHANGED
|
@@ -335,10 +335,25 @@ module.exports = {
|
|
|
335
335
|
press_key_return: "任意のキーを押してメインメニューに戻る...",
|
|
336
336
|
environment_variables: "環境変数:",
|
|
337
337
|
using_third_party_api: "サードパーティAPI設定を使用",
|
|
338
|
+
provider_optimizations_applied: "プロバイダー最適化が適用されました",
|
|
339
|
+
extended_timeout_format: "拡張タイムアウト:{0}秒({1}分)",
|
|
340
|
+
extended_timeout_format_singular: "拡張タイムアウト:{0}秒({1}分)",
|
|
341
|
+
non_essential_traffic_disabled: "必須でないトラフィックが無効",
|
|
342
|
+
custom_env_var: "{0}={1}",
|
|
343
|
+
// Deprecated - kept for backward compatibility
|
|
338
344
|
deepseek_optimizations: "DeepSeek最適化が有効:",
|
|
339
345
|
extended_timeout: "拡張タイムアウト (600秒)",
|
|
340
|
-
non_essential_disabled: "必須でないトラフィックが無効"
|
|
341
|
-
|
|
346
|
+
non_essential_disabled: "必須でないトラフィックが無効"
|
|
347
|
+
},
|
|
348
|
+
|
|
349
|
+
// プロバイダーノート
|
|
350
|
+
provider: {
|
|
351
|
+
note_prefix: "注意",
|
|
352
|
+
notes: {
|
|
353
|
+
deepseek: "複雑な推論タスクには拡張タイムアウトが必要です",
|
|
354
|
+
zhipu: "大規模な応答には拡張タイムアウトが必要です",
|
|
355
|
+
zai: "大規模な応答には拡張タイムアウトが必要です"
|
|
356
|
+
}
|
|
342
357
|
},
|
|
343
358
|
|
|
344
359
|
// 追加UIメッセージ
|
package/lib/i18n/locales/ko.js
CHANGED
|
@@ -335,10 +335,25 @@ module.exports = {
|
|
|
335
335
|
press_key_return: "아무 키나 눌러 메인 메뉴로 돌아가기...",
|
|
336
336
|
environment_variables: "환경 변수:",
|
|
337
337
|
using_third_party_api: "서드파티 API 설정 사용",
|
|
338
|
+
provider_optimizations_applied: "공급자 최적화 적용됨",
|
|
339
|
+
extended_timeout_format: "확장 타임아웃: {0}초 ({1}분)",
|
|
340
|
+
extended_timeout_format_singular: "확장 타임아웃: {0}초 ({1}분)",
|
|
341
|
+
non_essential_traffic_disabled: "필수가 아닌 트래픽 비활성화",
|
|
342
|
+
custom_env_var: "{0}={1}",
|
|
343
|
+
// Deprecated - kept for backward compatibility
|
|
338
344
|
deepseek_optimizations: "DeepSeek 최적화 활성화:",
|
|
339
345
|
extended_timeout: "확장 타임아웃 (600초)",
|
|
340
|
-
non_essential_disabled: "필수가 아닌 트래픽 비활성화"
|
|
341
|
-
|
|
346
|
+
non_essential_disabled: "필수가 아닌 트래픽 비활성화"
|
|
347
|
+
},
|
|
348
|
+
|
|
349
|
+
// 프로바이더 노트
|
|
350
|
+
provider: {
|
|
351
|
+
note_prefix: "참고",
|
|
352
|
+
notes: {
|
|
353
|
+
deepseek: "복잡한 추론 작업에는 확장 타임아웃이 필요합니다",
|
|
354
|
+
zhipu: "대용량 응답에는 확장 타임아웃이 필요합니다",
|
|
355
|
+
zai: "대용량 응답에는 확장 타임아웃이 필요합니다"
|
|
356
|
+
}
|
|
342
357
|
},
|
|
343
358
|
|
|
344
359
|
// 추가 UI 메시지
|
package/lib/i18n/locales/pt.js
CHANGED
|
@@ -335,11 +335,27 @@ module.exports = {
|
|
|
335
335
|
press_key_return: "Pressione qualquer tecla para voltar ao menu principal...",
|
|
336
336
|
environment_variables: "Variáveis de ambiente:",
|
|
337
337
|
using_third_party_api: "Usando Configuração de API de Terceiros",
|
|
338
|
+
provider_optimizations_applied: "Otimizações do provedor aplicadas",
|
|
339
|
+
extended_timeout_format: "Timeout estendido: {0}s ({1} minutos)",
|
|
340
|
+
extended_timeout_format_singular: "Timeout estendido: {0}s ({1} minuto)",
|
|
341
|
+
non_essential_traffic_disabled: "Tráfego não essencial desabilitado",
|
|
342
|
+
custom_env_var: "{0}={1}",
|
|
343
|
+
// Deprecated - kept for backward compatibility
|
|
338
344
|
deepseek_optimizations: "Otimizações DeepSeek habilitadas:",
|
|
339
345
|
extended_timeout: "Timeout estendido (600s)",
|
|
340
346
|
non_essential_disabled: "Tráfego não essencial desabilitado"
|
|
341
347
|
},
|
|
342
348
|
|
|
349
|
+
// Notas do provedor
|
|
350
|
+
provider: {
|
|
351
|
+
note_prefix: "Nota",
|
|
352
|
+
notes: {
|
|
353
|
+
deepseek: "Requer timeout estendido para tarefas de raciocínio complexas",
|
|
354
|
+
zhipu: "Requer timeout estendido para respostas grandes",
|
|
355
|
+
zai: "Requer timeout estendido para respostas grandes"
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
|
|
343
359
|
// Additional UI messages
|
|
344
360
|
ui: {
|
|
345
361
|
general: {
|
package/lib/i18n/locales/ru.js
CHANGED
|
@@ -335,11 +335,27 @@ module.exports = {
|
|
|
335
335
|
press_key_return: "Нажмите любую клавишу для возврата в главное меню...",
|
|
336
336
|
environment_variables: "Переменные окружения:",
|
|
337
337
|
using_third_party_api: "Использование конфигурации стороннего API",
|
|
338
|
+
provider_optimizations_applied: "Применены оптимизации провайдера",
|
|
339
|
+
extended_timeout_format: "Расширенный тайм-аут: {0}с ({1} минут)",
|
|
340
|
+
extended_timeout_format_singular: "Расширенный тайм-аут: {0}с ({1} минута)",
|
|
341
|
+
non_essential_traffic_disabled: "Несущественный трафик отключен",
|
|
342
|
+
custom_env_var: "{0}={1}",
|
|
343
|
+
// Deprecated - kept for backward compatibility
|
|
338
344
|
deepseek_optimizations: "Включены оптимизации DeepSeek:",
|
|
339
345
|
extended_timeout: "Расширенный тайм-аут (600s)",
|
|
340
346
|
non_essential_disabled: "Несущественный трафик отключен"
|
|
341
347
|
},
|
|
342
348
|
|
|
349
|
+
// Заметки провайдера
|
|
350
|
+
provider: {
|
|
351
|
+
note_prefix: "Примечание",
|
|
352
|
+
notes: {
|
|
353
|
+
deepseek: "Требуется расширенный тайм-аут для сложных задач рассуждения",
|
|
354
|
+
zhipu: "Требуется расширенный тайм-аут для больших ответов",
|
|
355
|
+
zai: "Требуется расширенный тайм-аут для больших ответов"
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
|
|
343
359
|
// Additional UI messages
|
|
344
360
|
ui: {
|
|
345
361
|
general: {
|
|
@@ -335,10 +335,25 @@ module.exports = {
|
|
|
335
335
|
press_key_return: "按任意鍵返回主選單...",
|
|
336
336
|
environment_variables: "環境變數:",
|
|
337
337
|
using_third_party_api: "使用第三方API設定",
|
|
338
|
+
provider_optimizations_applied: "提供商最佳化已啟用",
|
|
339
|
+
extended_timeout_format: "延長逾時時間:{0}秒({1}分鐘)",
|
|
340
|
+
extended_timeout_format_singular: "延長逾時時間:{0}秒({1}分鐘)",
|
|
341
|
+
non_essential_traffic_disabled: "非必要流量已停用",
|
|
342
|
+
custom_env_var: "{0}={1}",
|
|
343
|
+
// Deprecated - kept for backward compatibility
|
|
338
344
|
deepseek_optimizations: "DeepSeek 最佳化已啟用:",
|
|
339
345
|
extended_timeout: "延長逾時時間 (600秒)",
|
|
340
|
-
non_essential_disabled: "非必要流量已停用"
|
|
341
|
-
|
|
346
|
+
non_essential_disabled: "非必要流量已停用"
|
|
347
|
+
},
|
|
348
|
+
|
|
349
|
+
// 提供商備註
|
|
350
|
+
provider: {
|
|
351
|
+
note_prefix: "注意",
|
|
352
|
+
notes: {
|
|
353
|
+
deepseek: "複雜推理任務需要延長逾時時間",
|
|
354
|
+
zhipu: "大型回應需要延長逾時時間",
|
|
355
|
+
zai: "大型回應需要延長逾時時間"
|
|
356
|
+
}
|
|
342
357
|
},
|
|
343
358
|
|
|
344
359
|
// 額外UI訊息
|
package/lib/i18n/locales/zh.js
CHANGED
|
@@ -335,10 +335,25 @@ module.exports = {
|
|
|
335
335
|
press_key_return: "按任意键返回主菜单...",
|
|
336
336
|
environment_variables: "环境变量:",
|
|
337
337
|
using_third_party_api: "使用第三方API配置",
|
|
338
|
+
provider_optimizations_applied: "提供商优化已启用",
|
|
339
|
+
extended_timeout_format: "扩展超时时间:{0}秒({1}分钟)",
|
|
340
|
+
extended_timeout_format_singular: "扩展超时时间:{0}秒({1}分钟)",
|
|
341
|
+
non_essential_traffic_disabled: "非必要流量已禁用",
|
|
342
|
+
custom_env_var: "{0}={1}",
|
|
343
|
+
// Deprecated - kept for backward compatibility
|
|
338
344
|
deepseek_optimizations: "DeepSeek 优化已启用:",
|
|
339
345
|
extended_timeout: "扩展超时时间 (600秒)",
|
|
340
|
-
non_essential_disabled: "非必要流量已禁用"
|
|
341
|
-
|
|
346
|
+
non_essential_disabled: "非必要流量已禁用"
|
|
347
|
+
},
|
|
348
|
+
|
|
349
|
+
// Provider notes
|
|
350
|
+
provider: {
|
|
351
|
+
note_prefix: "注意",
|
|
352
|
+
notes: {
|
|
353
|
+
deepseek: "复杂推理任务需要扩展超时时间",
|
|
354
|
+
zhipu: "大型响应需要扩展超时时间",
|
|
355
|
+
zai: "大型响应需要扩展超时时间"
|
|
356
|
+
}
|
|
342
357
|
},
|
|
343
358
|
|
|
344
359
|
// 额外UI消息
|
package/lib/launcher.js
CHANGED
|
@@ -5,28 +5,33 @@
|
|
|
5
5
|
const { spawn } = require('child_process');
|
|
6
6
|
const colors = require('./ui/colors');
|
|
7
7
|
const i18n = require('./i18n');
|
|
8
|
+
const { getProvider } = require('./presets/providers');
|
|
9
|
+
const stdinManager = require('./utils/stdin-manager');
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Launch Claude Code with specified environment variables
|
|
11
13
|
*/
|
|
12
14
|
function launchClaude(command, envVars = {}, disableAuthTokens = false) {
|
|
15
|
+
// Disable Ctrl+C monitoring before launching Claude Code
|
|
16
|
+
// This allows Ctrl+C to be handled exclusively by Claude Code process
|
|
17
|
+
stdinManager.disableCtrlC();
|
|
18
|
+
|
|
13
19
|
console.log('');
|
|
14
|
-
console.log(colors.yellow + '
|
|
20
|
+
console.log(colors.yellow + '[*] ' + i18n.tSync('launch.starting') + colors.reset);
|
|
15
21
|
console.log(colors.gray + i18n.tSync('launch.command', command) + colors.reset);
|
|
16
22
|
|
|
17
23
|
if (Object.keys(envVars).length > 0) {
|
|
18
24
|
console.log(colors.gray + i18n.tSync('launch.environment_variables') + colors.reset);
|
|
25
|
+
// Mask sensitive environment variables based on key name patterns
|
|
26
|
+
const secretKeyRe = /(token|key|secret|pass|auth|credential)/i;
|
|
19
27
|
for (const [key, value] of Object.entries(envVars)) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
} else {
|
|
23
|
-
console.log(colors.gray + ` ${key}=${value}` + colors.reset);
|
|
24
|
-
}
|
|
28
|
+
const masked = secretKeyRe.test(key) ? '***' : String(value);
|
|
29
|
+
console.log(colors.gray + ' ' + key + '=' + masked + colors.reset);
|
|
25
30
|
}
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
console.log('');
|
|
29
|
-
console.log(colors.green + '
|
|
34
|
+
console.log(colors.green + '[>] ' + i18n.tSync('launch.run_in_terminal') + colors.reset);
|
|
30
35
|
console.log(colors.gray + ' ' + i18n.tSync('launch.launcher_exit') + colors.reset);
|
|
31
36
|
console.log('');
|
|
32
37
|
|
|
@@ -44,20 +49,103 @@ function launchClaude(command, envVars = {}, disableAuthTokens = false) {
|
|
|
44
49
|
const args = command.split(' ');
|
|
45
50
|
const cmd = args.shift();
|
|
46
51
|
|
|
52
|
+
let consoleRelinquished = false;
|
|
53
|
+
const relinquishConsoleToChild = () => {
|
|
54
|
+
if (consoleRelinquished) return;
|
|
55
|
+
consoleRelinquished = true;
|
|
56
|
+
// Do the minimal changes: switch to cooked mode and detach current scope, but do not pause stdin nor swallow signals
|
|
57
|
+
try {
|
|
58
|
+
if (process.stdin.isTTY) {
|
|
59
|
+
process.stdin.setRawMode(false);
|
|
60
|
+
}
|
|
61
|
+
} catch (_) {}
|
|
62
|
+
|
|
63
|
+
// Detach only current scope listeners to avoid affecting other modules
|
|
64
|
+
if (stdinManager.activeScope && typeof stdinManager.activeScope.detach === 'function') {
|
|
65
|
+
stdinManager.activeScope.detach();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Suspend stdin manager so no new listeners are attached while Claude is running
|
|
69
|
+
if (typeof stdinManager.suspend === 'function') {
|
|
70
|
+
stdinManager.suspend();
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const restoreConsoleForLauncher = () => {
|
|
75
|
+
if (!consoleRelinquished) return;
|
|
76
|
+
consoleRelinquished = false;
|
|
77
|
+
if (typeof stdinManager.resume === 'function') {
|
|
78
|
+
stdinManager.resume();
|
|
79
|
+
}
|
|
80
|
+
stdinManager.enableCtrlC();
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const handleLaunchFailure = (message, opts = {}) => {
|
|
84
|
+
if (opts.afterHandover) {
|
|
85
|
+
restoreConsoleForLauncher();
|
|
86
|
+
} else {
|
|
87
|
+
stdinManager.enableCtrlC();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
console.log(colors.red + '[x] ' + message + colors.reset);
|
|
91
|
+
console.log(colors.gray + i18n.tSync('ui.general.press_key_return_menu') + colors.reset);
|
|
92
|
+
|
|
93
|
+
if (process.stdin.isTTY) {
|
|
94
|
+
try {
|
|
95
|
+
process.stdin.setRawMode(true);
|
|
96
|
+
process.stdin.resume();
|
|
97
|
+
} catch (_) {
|
|
98
|
+
// Ignore setup failures
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Set timeout to prevent infinite hanging
|
|
102
|
+
const timeoutId = setTimeout(() => {
|
|
103
|
+
try {
|
|
104
|
+
process.stdin.setRawMode(false);
|
|
105
|
+
} catch (_) {
|
|
106
|
+
// Ignore cleanup failures
|
|
107
|
+
}
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}, 60000); // 60 second timeout
|
|
110
|
+
|
|
111
|
+
process.stdin.once('data', () => {
|
|
112
|
+
clearTimeout(timeoutId);
|
|
113
|
+
try {
|
|
114
|
+
process.stdin.setRawMode(false);
|
|
115
|
+
} catch (_) {
|
|
116
|
+
// Ignore cleanup failures
|
|
117
|
+
}
|
|
118
|
+
// Exit after user acknowledges the error
|
|
119
|
+
process.exit(1);
|
|
120
|
+
});
|
|
121
|
+
} else {
|
|
122
|
+
// For non-TTY environments, exit immediately
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
47
127
|
try {
|
|
48
128
|
// Clean up terminal state before launching Claude
|
|
49
129
|
if (process.stdin.isTTY) {
|
|
50
|
-
|
|
51
|
-
|
|
130
|
+
try {
|
|
131
|
+
process.stdin.setRawMode(false);
|
|
132
|
+
process.stdin.pause();
|
|
133
|
+
} catch (_) {
|
|
134
|
+
// Ignore cleanup failures
|
|
135
|
+
}
|
|
52
136
|
}
|
|
53
137
|
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
//
|
|
138
|
+
// Note: stdin listener management is handled by relinquishConsoleToChild()
|
|
139
|
+
// using stdinManager.activeScope.detach() and stdinManager.suspend().
|
|
140
|
+
// This ensures only the current scope's listeners are detached while
|
|
141
|
+
// preserving any listeners from other modules.
|
|
142
|
+
//
|
|
143
|
+
// Note: Do NOT remove global SIGINT/SIGTERM handlers here.
|
|
144
|
+
// The existing handlers already check stdinManager.isSuspended() and
|
|
145
|
+
// will properly ignore signals during child process execution.
|
|
146
|
+
// Removing all handlers would break other modules and degrade reliability.
|
|
147
|
+
|
|
148
|
+
// Launch Claude in current terminal, inherit stdio
|
|
61
149
|
const child = spawn(cmd, args, {
|
|
62
150
|
stdio: 'inherit',
|
|
63
151
|
env: env,
|
|
@@ -65,25 +153,19 @@ function launchClaude(command, envVars = {}, disableAuthTokens = false) {
|
|
|
65
153
|
shell: true
|
|
66
154
|
});
|
|
67
155
|
|
|
68
|
-
|
|
156
|
+
relinquishConsoleToChild();
|
|
157
|
+
|
|
69
158
|
child.on('close', (code) => {
|
|
159
|
+
restoreConsoleForLauncher();
|
|
70
160
|
process.exit(code || 0);
|
|
71
161
|
});
|
|
72
162
|
|
|
73
163
|
child.on('error', (error) => {
|
|
74
|
-
|
|
75
|
-
process.exit(1);
|
|
164
|
+
handleLaunchFailure('Error running Claude: ' + error.message, { afterHandover: true });
|
|
76
165
|
});
|
|
77
166
|
|
|
78
167
|
} catch (error) {
|
|
79
|
-
|
|
80
|
-
console.log(colors.gray + i18n.tSync('ui.general.press_key_return_menu') + colors.reset);
|
|
81
|
-
process.stdin.setRawMode(true);
|
|
82
|
-
process.stdin.resume();
|
|
83
|
-
process.stdin.once('data', () => {
|
|
84
|
-
process.stdin.setRawMode(false);
|
|
85
|
-
// Note: Caller should handle menu display
|
|
86
|
-
});
|
|
168
|
+
handleLaunchFailure('Error launching Claude Code: ' + error.message);
|
|
87
169
|
}
|
|
88
170
|
}
|
|
89
171
|
|
|
@@ -123,21 +205,18 @@ function getProviderEnvVars(api) {
|
|
|
123
205
|
ANTHROPIC_SMALL_FAST_MODEL: api.smallFastModel || api.model
|
|
124
206
|
};
|
|
125
207
|
|
|
126
|
-
//
|
|
127
|
-
|
|
128
|
-
case 'deepseek':
|
|
129
|
-
return {
|
|
130
|
-
...baseEnvVars,
|
|
131
|
-
API_TIMEOUT_MS: '600000',
|
|
132
|
-
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1'
|
|
133
|
-
};
|
|
208
|
+
// Get provider configuration and merge provider-specific environment variables
|
|
209
|
+
const providerConfig = getProvider(api.provider);
|
|
134
210
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
211
|
+
if (providerConfig && providerConfig.envVars) {
|
|
212
|
+
// Merge base env vars with provider-specific env vars
|
|
213
|
+
return {
|
|
214
|
+
...baseEnvVars,
|
|
215
|
+
...providerConfig.envVars
|
|
216
|
+
};
|
|
140
217
|
}
|
|
218
|
+
|
|
219
|
+
return baseEnvVars;
|
|
141
220
|
}
|
|
142
221
|
|
|
143
222
|
/**
|
|
@@ -152,16 +231,43 @@ function launchClaudeWithApi(api, skipPermissions = false) {
|
|
|
152
231
|
|
|
153
232
|
console.log('');
|
|
154
233
|
console.log(colors.bright + colors.orange + '🔗 ' + i18n.tSync('launch.using_third_party_api') + colors.reset);
|
|
155
|
-
|
|
234
|
+
|
|
235
|
+
// Get provider configuration for display
|
|
236
|
+
const providerConfig = getProvider(api.provider);
|
|
237
|
+
const providerName = providerConfig ? providerConfig.name : (api.provider || 'Custom');
|
|
238
|
+
|
|
239
|
+
console.log(colors.gray + ` Provider: ${providerName}` + colors.reset);
|
|
156
240
|
console.log(colors.gray + ` API: ${api.name}` + colors.reset);
|
|
157
241
|
console.log(colors.gray + ` Base URL: ${api.baseUrl}` + colors.reset);
|
|
158
242
|
console.log(colors.gray + ` Model: ${api.model}` + colors.reset);
|
|
159
243
|
|
|
160
|
-
// Show provider-specific optimizations
|
|
161
|
-
if (
|
|
162
|
-
console.log(colors.yellow + ' ⚡ ' + i18n.tSync('launch.
|
|
163
|
-
|
|
164
|
-
|
|
244
|
+
// Show provider-specific optimizations if envVars are defined
|
|
245
|
+
if (providerConfig && providerConfig.envVars && Object.keys(providerConfig.envVars).length > 0) {
|
|
246
|
+
console.log(colors.yellow + ' ⚡ ' + i18n.tSync('launch.provider_optimizations_applied') + colors.reset);
|
|
247
|
+
|
|
248
|
+
// Display specific optimizations based on envVars
|
|
249
|
+
const msRaw = providerConfig.envVars.API_TIMEOUT_MS;
|
|
250
|
+
const ms = Number(msRaw);
|
|
251
|
+
if (Number.isFinite(ms) && ms > 0) {
|
|
252
|
+
const timeoutSec = Math.floor(ms / 1000);
|
|
253
|
+
const timeoutMin = Math.floor(timeoutSec / 60);
|
|
254
|
+
// Use singular or plural form based on timeoutMin value
|
|
255
|
+
const key = timeoutMin === 1 ? 'launch.extended_timeout_format_singular' : 'launch.extended_timeout_format';
|
|
256
|
+
console.log(colors.gray + ' • ' + i18n.tSync(key, timeoutSec, timeoutMin) + colors.reset);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (providerConfig.envVars.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC) {
|
|
260
|
+
console.log(colors.gray + ' • ' + i18n.tSync('launch.non_essential_traffic_disabled') + colors.reset);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Display any other custom env vars (excluding the ones already shown)
|
|
264
|
+
// Apply same masking logic as in launchClaude to protect sensitive values
|
|
265
|
+
const secretKeyRe = /(token|key|secret|pass|auth|credential)/i;
|
|
266
|
+
for (const [key, value] of Object.entries(providerConfig.envVars)) {
|
|
267
|
+
if (key === 'API_TIMEOUT_MS' || key === 'CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC') continue;
|
|
268
|
+
const masked = secretKeyRe.test(key) ? '***' : String(value);
|
|
269
|
+
console.log(colors.gray + ' • ' + i18n.tSync('launch.custom_env_var', key, masked) + colors.reset);
|
|
270
|
+
}
|
|
165
271
|
}
|
|
166
272
|
|
|
167
273
|
console.log('');
|
|
@@ -250,4 +356,4 @@ module.exports = {
|
|
|
250
356
|
launchClaudeWithApi,
|
|
251
357
|
getProviderEnvVars,
|
|
252
358
|
testApiConnection
|
|
253
|
-
};
|
|
359
|
+
};
|
package/lib/presets/providers.js
CHANGED
|
@@ -31,7 +31,12 @@ const providers = {
|
|
|
31
31
|
authTokenFormat: 'sk-...',
|
|
32
32
|
description: 'Moonshot AI - Provides Anthropic-compatible API',
|
|
33
33
|
requiresToken: true,
|
|
34
|
-
compatibility: 'anthropic-compatible'
|
|
34
|
+
compatibility: 'anthropic-compatible',
|
|
35
|
+
envVars: {
|
|
36
|
+
API_TIMEOUT_MS: '3000000',
|
|
37
|
+
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1'
|
|
38
|
+
},
|
|
39
|
+
note: 'Requires extended timeout for large responses'
|
|
35
40
|
},
|
|
36
41
|
deepseek: {
|
|
37
42
|
name: 'DeepSeek (DeepSeek V3/V3.1)',
|
|
@@ -42,7 +47,46 @@ const providers = {
|
|
|
42
47
|
authTokenFormat: 'sk-...',
|
|
43
48
|
description: 'DeepSeek AI - Anthropic-compatible endpoint',
|
|
44
49
|
requiresToken: true,
|
|
45
|
-
compatibility: 'anthropic-compatible'
|
|
50
|
+
compatibility: 'anthropic-compatible',
|
|
51
|
+
envVars: {
|
|
52
|
+
API_TIMEOUT_MS: '600000',
|
|
53
|
+
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1'
|
|
54
|
+
},
|
|
55
|
+
note: 'Requires extended timeout for complex reasoning tasks'
|
|
56
|
+
},
|
|
57
|
+
zhipu: {
|
|
58
|
+
name: 'ZhiPu AI (GLM-4.5/4.6) - 智谱清言',
|
|
59
|
+
baseUrl: 'https://open.bigmodel.cn/api/anthropic',
|
|
60
|
+
models: [
|
|
61
|
+
'glm-4.5',
|
|
62
|
+
'glm-4.6'
|
|
63
|
+
],
|
|
64
|
+
authTokenFormat: 'sk-...',
|
|
65
|
+
description: 'ZhiPu AI (智谱清言) - Anthropic-compatible API for mainland China',
|
|
66
|
+
requiresToken: true,
|
|
67
|
+
compatibility: 'anthropic-compatible',
|
|
68
|
+
envVars: {
|
|
69
|
+
API_TIMEOUT_MS: '3000000',
|
|
70
|
+
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1'
|
|
71
|
+
},
|
|
72
|
+
note: 'Requires extended timeout for large responses'
|
|
73
|
+
},
|
|
74
|
+
zai: {
|
|
75
|
+
name: 'Z.ai (GLM-4.5/4.6) - ZhiPu Global',
|
|
76
|
+
baseUrl: 'https://api.z.ai/api/anthropic',
|
|
77
|
+
models: [
|
|
78
|
+
'glm-4.5',
|
|
79
|
+
'glm-4.6'
|
|
80
|
+
],
|
|
81
|
+
authTokenFormat: 'sk-...',
|
|
82
|
+
description: 'Z.ai (ZhiPu AI Global) - Anthropic-compatible API for international users',
|
|
83
|
+
requiresToken: true,
|
|
84
|
+
compatibility: 'anthropic-compatible',
|
|
85
|
+
envVars: {
|
|
86
|
+
API_TIMEOUT_MS: '3000000',
|
|
87
|
+
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1'
|
|
88
|
+
},
|
|
89
|
+
note: 'Requires extended timeout for large responses'
|
|
46
90
|
},
|
|
47
91
|
custom: {
|
|
48
92
|
name: 'Custom Anthropic-Compatible API',
|