coding-tool-x 3.6.0 → 3.6.1
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
|
@@ -18,6 +18,7 @@ const channelHealth = new Map(); // `${source}:${channelId}` → health info
|
|
|
18
18
|
|
|
19
19
|
// 冻结回调(用于通知调度器解绑会话)
|
|
20
20
|
let onChannelFrozenCallback = null;
|
|
21
|
+
let channelListProvider = null;
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* 设置渠道冻结时的回调
|
|
@@ -26,6 +27,10 @@ function setOnChannelFrozen(callback) {
|
|
|
26
27
|
onChannelFrozenCallback = callback;
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
function setChannelListProvider(provider) {
|
|
31
|
+
channelListProvider = typeof provider === 'function' ? provider : null;
|
|
32
|
+
}
|
|
33
|
+
|
|
29
34
|
/**
|
|
30
35
|
* 初始化渠道健康信息
|
|
31
36
|
*/
|
|
@@ -69,6 +74,40 @@ function transitionFrozenChannelIfExpired(channelId, source = 'claude') {
|
|
|
69
74
|
return health;
|
|
70
75
|
}
|
|
71
76
|
|
|
77
|
+
function getEnabledChannels(source = 'claude') {
|
|
78
|
+
if (!channelListProvider) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
const channels = channelListProvider(source || 'claude');
|
|
84
|
+
if (!Array.isArray(channels)) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
return channels.filter(channel => channel && channel.enabled !== false);
|
|
88
|
+
} catch (err) {
|
|
89
|
+
console.warn(`[ChannelHealth] Failed to inspect ${source || 'claude'} channels before freezing: ${err.message}`);
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function isLastAvailableChannel(channelId, source = 'claude') {
|
|
95
|
+
const enabledChannels = getEnabledChannels(source);
|
|
96
|
+
if (!enabledChannels) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const currentExists = enabledChannels.some(channel => channel.id === channelId);
|
|
101
|
+
if (!currentExists) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const availableChannels = enabledChannels.filter(channel =>
|
|
106
|
+
channel.id === channelId || isChannelAvailable(channel.id, source)
|
|
107
|
+
);
|
|
108
|
+
return availableChannels.length <= 1;
|
|
109
|
+
}
|
|
110
|
+
|
|
72
111
|
/**
|
|
73
112
|
* 记录成功请求
|
|
74
113
|
*/
|
|
@@ -107,6 +146,11 @@ function recordFailure(channelId, source = 'claude', error) {
|
|
|
107
146
|
// 如果当前是健康状态或检测中状态,检查是否需要冻结
|
|
108
147
|
if (health.status === 'healthy' || health.status === 'checking') {
|
|
109
148
|
if (health.consecutiveFailures >= healthConfig.failureThreshold) {
|
|
149
|
+
if (isLastAvailableChannel(channelId, source)) {
|
|
150
|
+
console.warn(`[ChannelHealth] Channel ${channelId} reached failure threshold but remains active because it is the last available ${source || 'claude'} channel`);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
110
154
|
// 触发冻结
|
|
111
155
|
const previousStatus = health.status;
|
|
112
156
|
health.status = 'frozen';
|
|
@@ -241,5 +285,6 @@ module.exports = {
|
|
|
241
285
|
getAllChannelHealthStatus,
|
|
242
286
|
resetChannelHealth,
|
|
243
287
|
setOnChannelFrozen,
|
|
288
|
+
setChannelListProvider,
|
|
244
289
|
healthConfig,
|
|
245
290
|
};
|
|
@@ -2,7 +2,7 @@ const { getAllChannels } = require('./channels');
|
|
|
2
2
|
const { getChannels: getCodexChannels } = require('./codex-channels');
|
|
3
3
|
const { getChannels: getGeminiChannels } = require('./gemini-channels');
|
|
4
4
|
const { getChannels: getOpenCodeChannels } = require('./opencode-channels');
|
|
5
|
-
const { isChannelAvailable, getChannelHealthStatus, setOnChannelFrozen } = require('./channel-health');
|
|
5
|
+
const { isChannelAvailable, getChannelHealthStatus, setOnChannelFrozen, setChannelListProvider } = require('./channel-health');
|
|
6
6
|
|
|
7
7
|
const channelProviders = {
|
|
8
8
|
claude: () => getAllChannels(),
|
|
@@ -64,6 +64,11 @@ function unbindChannelSessions(source, channelId) {
|
|
|
64
64
|
|
|
65
65
|
// 注册冻结回调,当渠道被冻结时解绑其会话
|
|
66
66
|
setOnChannelFrozen(unbindChannelSessions);
|
|
67
|
+
setChannelListProvider((source = 'claude') => {
|
|
68
|
+
const provider = channelProviders[source || 'claude'];
|
|
69
|
+
if (!provider) return [];
|
|
70
|
+
return provider();
|
|
71
|
+
});
|
|
67
72
|
|
|
68
73
|
function refreshChannels(source = 'claude') {
|
|
69
74
|
const state = getState(source);
|