@adversity/coding-tool-x 3.0.1 → 3.0.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.
@@ -5,7 +5,7 @@
5
5
  <link rel="icon" href="/favicon.ico">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
7
  <title>CC-TOOL - ClaudeCode增强工作助手</title>
8
- <script type="module" crossorigin src="/assets/index-DfPKAt9R.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-BDN4_LfP.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/vue-vendor-6JaYHOiI.js">
10
10
  <link rel="modulepreload" crossorigin href="/assets/vendors-D2HHw_aW.js">
11
11
  <link rel="modulepreload" crossorigin href="/assets/icons-BlzwYoRU.js">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adversity/coding-tool-x",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "description": "Vibe Coding 增强工作助手 - 智能会话管理、动态渠道切换、全局搜索、实时监控",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -52,26 +52,47 @@ const PROVIDER_CAPABILITIES = {
52
52
  * @returns {string} - 'claude' | 'codex' | 'gemini' | 'openai_compatible'
53
53
  */
54
54
  function detectChannelType(channel) {
55
- const baseUrl = channel.baseUrl.toLowerCase();
55
+ try {
56
+ // Parse the URL to extract hostname
57
+ const parsedUrl = new URL(channel.baseUrl);
58
+ const hostname = parsedUrl.hostname.toLowerCase();
56
59
 
57
- // Check if it's official Anthropic API
58
- if (baseUrl.includes('anthropic.com') || baseUrl.includes('claude.ai')) {
59
- return 'claude';
60
- }
60
+ // Check if it's official Anthropic API (hostname only, not path)
61
+ if (hostname.includes('anthropic.com') || hostname.includes('claude.ai')) {
62
+ return 'claude';
63
+ }
61
64
 
62
- // Check if it's Gemini
63
- if (baseUrl.includes('generativelanguage.googleapis.com') || baseUrl.includes('gemini')) {
64
- return 'gemini';
65
- }
65
+ // Check if it's Gemini (hostname only)
66
+ if (hostname.includes('generativelanguage.googleapis.com') || hostname.includes('gemini')) {
67
+ return 'gemini';
68
+ }
66
69
 
67
- // Check if it's OpenAI official
68
- if (baseUrl.includes('api.openai.com')) {
69
- return 'codex';
70
- }
70
+ // Check if it's OpenAI official (hostname only)
71
+ if (hostname.includes('api.openai.com')) {
72
+ return 'codex';
73
+ }
74
+
75
+ // All other third-party proxies default to OpenAI compatible
76
+ // Including: 88code, anyrouter, internal proxies, etc.
77
+ // This correctly handles URLs like https://code.newcli.com/claude/aws
78
+ return 'openai_compatible';
79
+ } catch (error) {
80
+ // If URL parsing fails, fall back to string matching on full URL
81
+ console.warn(`[ModelDetector] Failed to parse URL ${channel.baseUrl}: ${error.message}`);
82
+ const baseUrl = channel.baseUrl.toLowerCase();
83
+
84
+ if (baseUrl.includes('anthropic.com') || baseUrl.includes('claude.ai')) {
85
+ return 'claude';
86
+ }
87
+ if (baseUrl.includes('generativelanguage.googleapis.com')) {
88
+ return 'gemini';
89
+ }
90
+ if (baseUrl.includes('api.openai.com')) {
91
+ return 'codex';
92
+ }
71
93
 
72
- // All other third-party proxies default to OpenAI compatible
73
- // Including: 88code, anyrouter, internal proxies, etc.
74
- return 'openai_compatible';
94
+ return 'openai_compatible';
95
+ }
75
96
  }
76
97
 
77
98
  // Model name normalization mapping
@@ -509,14 +530,53 @@ async function fetchModelsFromProvider(channel, channelType) {
509
530
  });
510
531
  }
511
532
  } else if (res.statusCode === 401 || res.statusCode === 403) {
512
- console.error(`[ModelDetector] Authentication failed for ${channel.name}: ${res.statusCode}`);
513
- resolve({
514
- models: [],
515
- supported: true,
516
- cached: false,
517
- fallbackUsed: true,
518
- error: `Authentication failed: ${res.statusCode}`
519
- });
533
+ // Check if it's a Cloudflare protection issue
534
+ const bodyLower = data.toLowerCase();
535
+ const isCloudflare = bodyLower.includes('cloudflare') || bodyLower.includes('challenge') || bodyLower.includes('cf-ray');
536
+
537
+ let errorMessage;
538
+ let errorHint;
539
+
540
+ if (isCloudflare) {
541
+ errorMessage = 'Cloudflare 防护拦截,已使用默认模型';
542
+ errorHint = '该 API 端点受 Cloudflare 保护,已自动使用默认模型 claude-sonnet-4-5';
543
+ console.warn(`[ModelDetector] Cloudflare protection detected for ${channel.name}, using default model`);
544
+ resolve({
545
+ models: ['claude-sonnet-4-5'],
546
+ supported: true,
547
+ cached: false,
548
+ fallbackUsed: true,
549
+ error: errorMessage,
550
+ errorHint: errorHint,
551
+ statusCode: res.statusCode
552
+ });
553
+ } else if (res.statusCode === 401) {
554
+ errorMessage = 'API 密钥认证失败';
555
+ errorHint = '请检查 API 密钥是否正确配置';
556
+ console.error(`[ModelDetector] Authentication failed for ${channel.name}: ${res.statusCode} - ${errorMessage}`);
557
+ resolve({
558
+ models: [],
559
+ supported: true,
560
+ cached: false,
561
+ fallbackUsed: true,
562
+ error: errorMessage,
563
+ errorHint: errorHint,
564
+ statusCode: res.statusCode
565
+ });
566
+ } else {
567
+ errorMessage = '访问被拒绝';
568
+ errorHint = '请检查 API 密钥权限或联系服务提供商';
569
+ console.error(`[ModelDetector] Access denied for ${channel.name}: ${res.statusCode} - ${errorMessage}`);
570
+ resolve({
571
+ models: [],
572
+ supported: true,
573
+ cached: false,
574
+ fallbackUsed: true,
575
+ error: errorMessage,
576
+ errorHint: errorHint,
577
+ statusCode: res.statusCode
578
+ });
579
+ }
520
580
  } else if (res.statusCode === 404) {
521
581
  console.warn(`[ModelDetector] Model list endpoint not found for ${channel.name}`);
522
582
  resolve({
@@ -524,7 +584,9 @@ async function fetchModelsFromProvider(channel, channelType) {
524
584
  supported: false,
525
585
  cached: false,
526
586
  fallbackUsed: true,
527
- error: 'Endpoint not found (404)'
587
+ error: '模型列表端点不存在',
588
+ errorHint: '该 API 可能不支持 /v1/models 接口,请手动输入模型名称',
589
+ statusCode: 404
528
590
  });
529
591
  } else if (res.statusCode === 429) {
530
592
  console.warn(`[ModelDetector] Rate limited for ${channel.name}`);
@@ -533,7 +595,9 @@ async function fetchModelsFromProvider(channel, channelType) {
533
595
  supported: true,
534
596
  cached: false,
535
597
  fallbackUsed: true,
536
- error: 'Rate limited (429)'
598
+ error: '请求频率限制',
599
+ errorHint: '请稍后再试或联系服务提供商提高限额',
600
+ statusCode: 429
537
601
  });
538
602
  } else {
539
603
  console.error(`[ModelDetector] Unexpected status ${res.statusCode} for ${channel.name}`);
@@ -542,7 +606,9 @@ async function fetchModelsFromProvider(channel, channelType) {
542
606
  supported: true,
543
607
  cached: false,
544
608
  fallbackUsed: true,
545
- error: `HTTP ${res.statusCode}`
609
+ error: `HTTP 错误 ${res.statusCode}`,
610
+ errorHint: '请检查 API 端点配置或联系服务提供商',
611
+ statusCode: res.statusCode
546
612
  });
547
613
  }
548
614
  });