@kikkimo/claude-launcher 2.0.0 → 2.2.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.
@@ -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: {
@@ -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
- press_key_return: "任意のキーを押してメインメニューに戻る..."
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メッセージ
@@ -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
- press_key_return: "아무 키나 눌러 메인 메뉴로 돌아가기..."
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 메시지
@@ -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: {
@@ -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
- press_key_return: "按任意鍵返回主選單..."
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訊息
@@ -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
- press_key_return: "按任意键返回主菜单..."
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 + '🚀 ' + i18n.tSync('launch.starting') + colors.reset);
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
- if (key.includes('TOKEN') || key.includes('KEY')) {
21
- console.log(colors.gray + ` ${key}=***` + colors.reset);
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 + ' ' + i18n.tSync('launch.run_in_terminal') + colors.reset);
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
- process.stdin.setRawMode(false);
51
- process.stdin.pause();
130
+ try {
131
+ process.stdin.setRawMode(false);
132
+ process.stdin.pause();
133
+ } catch (_) {
134
+ // Ignore cleanup failures
135
+ }
52
136
  }
53
137
 
54
- // Remove all event listeners to avoid conflicts
55
- process.stdin.removeAllListeners('data');
56
- process.stdin.removeAllListeners('keypress');
57
- process.removeAllListeners('SIGINT');
58
- process.removeAllListeners('SIGTERM');
59
-
60
- // Launch Claude in current terminal, let it inherit everything
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
- // Don't exit immediately, wait for Claude to exit then exit launcher
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
- console.log(colors.red + 'Error running Claude: ' + error.message + colors.reset);
75
- process.exit(1);
164
+ handleLaunchFailure('Error running Claude: ' + error.message, { afterHandover: true });
76
165
  });
77
166
 
78
167
  } catch (error) {
79
- console.log(colors.red + 'Error launching Claude Code: ' + error.message + colors.reset);
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
- // Add provider-specific environment variables
127
- switch (api.provider) {
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
- case 'moonshot':
136
- case 'anthropic':
137
- case 'custom':
138
- default:
139
- return baseEnvVars;
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
- console.log(colors.gray + ` Provider: ${api.provider || 'Custom'}` + colors.reset);
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 (api.provider === 'deepseek') {
162
- console.log(colors.yellow + ' ⚡ ' + i18n.tSync('launch.deepseek_optimizations') + colors.reset);
163
- console.log(colors.gray + ' • ' + i18n.tSync('launch.extended_timeout') + colors.reset);
164
- console.log(colors.gray + ' • ' + i18n.tSync('launch.non_essential_disabled') + colors.reset);
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
+ };
@@ -26,12 +26,35 @@ const providers = {
26
26
  models: [
27
27
  'kimi-k2-0711-preview',
28
28
  'kimi-k2-0905-preview',
29
- 'kimi-k2-turbo-preview'
29
+ 'kimi-k2-turbo-preview',
30
+ 'kimi-k2-thinking',
31
+ 'kimi-k2-thinking-turbo'
30
32
  ],
31
33
  authTokenFormat: 'sk-...',
32
34
  description: 'Moonshot AI - Provides Anthropic-compatible API',
33
35
  requiresToken: true,
34
- compatibility: 'anthropic-compatible'
36
+ compatibility: 'anthropic-compatible',
37
+ envVars: {
38
+ API_TIMEOUT_MS: '3000000',
39
+ CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1'
40
+ },
41
+ note: 'Requires extended timeout for large responses'
42
+ },
43
+ kimi_for_coding: {
44
+ name: 'Moonshot AI (Kimi for coding)',
45
+ baseUrl: 'https://api.kimi.com/coding',
46
+ models: [
47
+ 'kimi-for-coding'
48
+ ],
49
+ authTokenFormat: 'sk-...',
50
+ description: 'Moonshot AI - Specialized coding model endpoint',
51
+ requiresToken: true,
52
+ compatibility: 'anthropic-compatible',
53
+ envVars: {
54
+ API_TIMEOUT_MS: '3000000',
55
+ CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1'
56
+ },
57
+ note: 'Requires extended timeout for large responses'
35
58
  },
36
59
  deepseek: {
37
60
  name: 'DeepSeek (DeepSeek V3/V3.1)',
@@ -42,7 +65,46 @@ const providers = {
42
65
  authTokenFormat: 'sk-...',
43
66
  description: 'DeepSeek AI - Anthropic-compatible endpoint',
44
67
  requiresToken: true,
45
- compatibility: 'anthropic-compatible'
68
+ compatibility: 'anthropic-compatible',
69
+ envVars: {
70
+ API_TIMEOUT_MS: '600000',
71
+ CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1'
72
+ },
73
+ note: 'Requires extended timeout for complex reasoning tasks'
74
+ },
75
+ zhipu: {
76
+ name: 'ZhiPu AI (GLM-4.5/4.6) - 智谱清言',
77
+ baseUrl: 'https://open.bigmodel.cn/api/anthropic',
78
+ models: [
79
+ 'glm-4.5',
80
+ 'glm-4.6'
81
+ ],
82
+ authTokenFormat: 'sk-...',
83
+ description: 'ZhiPu AI (智谱清言) - Anthropic-compatible API for mainland China',
84
+ requiresToken: true,
85
+ compatibility: 'anthropic-compatible',
86
+ envVars: {
87
+ API_TIMEOUT_MS: '3000000',
88
+ CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1'
89
+ },
90
+ note: 'Requires extended timeout for large responses'
91
+ },
92
+ zai: {
93
+ name: 'Z.ai (GLM-4.5/4.6) - ZhiPu Global',
94
+ baseUrl: 'https://api.z.ai/api/anthropic',
95
+ models: [
96
+ 'glm-4.5',
97
+ 'glm-4.6'
98
+ ],
99
+ authTokenFormat: 'sk-...',
100
+ description: 'Z.ai (ZhiPu AI Global) - Anthropic-compatible API for international users',
101
+ requiresToken: true,
102
+ compatibility: 'anthropic-compatible',
103
+ envVars: {
104
+ API_TIMEOUT_MS: '3000000',
105
+ CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1'
106
+ },
107
+ note: 'Requires extended timeout for large responses'
46
108
  },
47
109
  custom: {
48
110
  name: 'Custom Anthropic-Compatible API',