claw-subagent-service 0.0.125 → 0.0.127
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
|
@@ -136,121 +136,43 @@ async function verifyCommandResult(command, result, scriptOutput = '') {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
if (command === OpenClawCommandEnum.STOP) {
|
|
139
|
-
//
|
|
139
|
+
// 停止命令验证:快速检查端口状态
|
|
140
140
|
console.log(`[OpenClawControl] 开始验证停止结果...`);
|
|
141
141
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const
|
|
142
|
+
// 等待 2 秒后检查
|
|
143
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
144
|
+
const portStatus = await getOpenClawStatus(18789);
|
|
145
|
+
console.log(`[OpenClawControl] 停止后端口状态: ${portStatus}`);
|
|
145
146
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
portStatus = await getOpenClawStatus(18789);
|
|
151
|
-
console.log(`[OpenClawControl] 停止后端口状态 (尝试 ${stopAttempts + 1}/${maxStopAttempts}): ${portStatus}`);
|
|
152
|
-
|
|
153
|
-
if (portStatus !== 1) {
|
|
154
|
-
console.log(`[OpenClawControl] 停止验证通过: 端口已关闭`);
|
|
155
|
-
break;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
stopAttempts++;
|
|
159
|
-
if (stopAttempts < maxStopAttempts) {
|
|
160
|
-
console.log(`[OpenClawControl] 端口仍在监听,尝试第 ${stopAttempts + 1} 次停止...`);
|
|
161
|
-
const scriptResult = await executeWithScript(command);
|
|
162
|
-
const retryResult = scriptResult.result;
|
|
163
|
-
console.log(`[OpenClawControl] 第 ${stopAttempts} 次重试停止结果: ${retryResult.status} - ${retryResult.message}`);
|
|
164
|
-
|
|
165
|
-
// 等待看门狗重启后再检查
|
|
166
|
-
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (portStatus === 1) {
|
|
171
|
-
console.error(`[OpenClawControl] 停止失败: 端口 18789 仍在监听。尝试直接强制终止进程...`);
|
|
172
|
-
|
|
173
|
-
// 直接执行强制终止命令(不通过脚本)
|
|
174
|
-
try {
|
|
175
|
-
const { execSync } = require('child_process');
|
|
176
|
-
|
|
177
|
-
// 先尝试 pkill
|
|
178
|
-
try {
|
|
179
|
-
execSync('pkill -9 -f "openclaw"', { timeout: 5000 });
|
|
180
|
-
console.log('[OpenClawControl] pkill -9 -f openclaw 执行成功');
|
|
181
|
-
} catch (e) {
|
|
182
|
-
console.log('[OpenClawControl] pkill 执行失败或没有匹配进程');
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// 再尝试 killall
|
|
186
|
-
try {
|
|
187
|
-
execSync('killall -9 openclaw', { timeout: 5000 });
|
|
188
|
-
console.log('[OpenClawControl] killall -9 openclaw 执行成功');
|
|
189
|
-
} catch (e) {
|
|
190
|
-
console.log('[OpenClawControl] killall 执行失败或没有匹配进程');
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// 等待进程退出
|
|
194
|
-
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
195
|
-
|
|
196
|
-
// 再次验证端口
|
|
197
|
-
const finalPortStatus = await getOpenClawStatus(18789);
|
|
198
|
-
|
|
199
|
-
if (finalPortStatus !== 1) {
|
|
200
|
-
console.log(`[OpenClawControl] 强制停止成功: 端口已关闭`);
|
|
201
|
-
return {
|
|
202
|
-
status: OpenClawServiceStatus.STOP_SUCCESS,
|
|
203
|
-
message: '服务已停止(强制停止)'
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
} catch (err) {
|
|
207
|
-
console.error(`[OpenClawControl] 强制停止异常: ${err.message}`);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
console.error(`[OpenClawControl] 停止失败: 端口 18789 仍在监听。所有停止方法均已尝试。`);
|
|
147
|
+
if (portStatus !== 1) {
|
|
148
|
+
console.log(`[OpenClawControl] 停止验证通过: 端口已关闭`);
|
|
149
|
+
} else {
|
|
150
|
+
console.error(`[OpenClawControl] 停止失败: 端口 18789 仍在监听。`);
|
|
211
151
|
return {
|
|
212
152
|
status: OpenClawServiceStatus.ERROR,
|
|
213
153
|
message: '停止失败: 服务仍在运行'
|
|
214
154
|
};
|
|
215
155
|
}
|
|
216
|
-
|
|
217
|
-
console.log(`[OpenClawControl] 停止验证通过: 端口已关闭`);
|
|
218
156
|
} else if (command === OpenClawCommandEnum.START || command === OpenClawCommandEnum.RESTART) {
|
|
219
|
-
//
|
|
220
|
-
const maxWait =
|
|
157
|
+
// 等待服务启动(最多等待 30 秒)
|
|
158
|
+
const maxWait = 15; // 最多 15 次检查
|
|
221
159
|
let attempts = 0;
|
|
222
160
|
let portStatus = 0;
|
|
223
161
|
|
|
224
162
|
while (attempts < maxWait) {
|
|
225
163
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
226
164
|
portStatus = await getOpenClawStatus(18789);
|
|
227
|
-
if (portStatus === 1
|
|
165
|
+
if (portStatus === 1) break; // 端口监听算成功
|
|
228
166
|
attempts++;
|
|
229
167
|
}
|
|
230
168
|
|
|
231
169
|
console.log(`[OpenClawControl] ${getCommandName(command)}后端口状态: ${portStatus}`);
|
|
232
170
|
|
|
233
171
|
if (portStatus === 0) {
|
|
234
|
-
// 端口未监听且进程不存在,但检查脚本是否报告成功
|
|
235
|
-
if (outputUpper.includes('SUCCESS') || outputUpper.includes('ALREADY RUNNING')) {
|
|
236
|
-
console.warn(`[OpenClawControl] 警告: 端口检查失败,但脚本报告成功。服务可能绑定到其他网络接口。`);
|
|
237
|
-
// 信任脚本结果,但添加警告
|
|
238
|
-
return {
|
|
239
|
-
status: result.status,
|
|
240
|
-
message: result.message + ' (警告: 端口检查可能不准确)'
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
172
|
return {
|
|
244
173
|
status: OpenClawServiceStatus.ERROR,
|
|
245
174
|
message: `${getCommandName(command)}失败: 服务未运行`
|
|
246
175
|
};
|
|
247
|
-
} else if (portStatus === 2) {
|
|
248
|
-
// 进程存在但端口未监听,服务可能在启动中或绑定到其他地址
|
|
249
|
-
console.warn(`[OpenClawControl] 警告: openclaw 进程存在但端口 ${portStatus} 未监听。`);
|
|
250
|
-
return {
|
|
251
|
-
status: result.status === OpenClawServiceStatus.START_SUCCESS ? result.status : OpenClawServiceStatus.START_SUCCESS,
|
|
252
|
-
message: result.message + ' (进程已启动,端口检查可能不准确)'
|
|
253
|
-
};
|
|
254
176
|
}
|
|
255
177
|
}
|
|
256
178
|
|
|
@@ -40,9 +40,21 @@ function isValidCommand(command) {
|
|
|
40
40
|
return Object.values(OpenClawCommandEnum).includes(command);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
function getCommandName(command) {
|
|
44
|
+
const names = {
|
|
45
|
+
[OpenClawCommandEnum.START]: '启动',
|
|
46
|
+
[OpenClawCommandEnum.STOP]: '停止',
|
|
47
|
+
[OpenClawCommandEnum.RESTART]: '重启',
|
|
48
|
+
[OpenClawCommandEnum.STATUS]: '状态检查',
|
|
49
|
+
[OpenClawCommandEnum.CONFIG_FIX]: '配置修复'
|
|
50
|
+
};
|
|
51
|
+
return names[command] || '未知命令';
|
|
52
|
+
}
|
|
53
|
+
|
|
43
54
|
module.exports = {
|
|
44
55
|
OpenClawCommandEnum,
|
|
45
56
|
OpenClawServiceStatus,
|
|
46
57
|
getServiceStatusMessage,
|
|
47
|
-
isValidCommand
|
|
58
|
+
isValidCommand,
|
|
59
|
+
getCommandName
|
|
48
60
|
};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - DELETE_OPENCODE_SESSION: 删除会话
|
|
9
9
|
*/
|
|
10
10
|
const { RongyunMessageTypeEnum } = require('./rongyun-message-types');
|
|
11
|
-
const { OpenClawCommandEnum } = require('./openclaw-enum');
|
|
11
|
+
const { OpenClawCommandEnum, getCommandName } = require('./openclaw-enum');
|
|
12
12
|
const { executeCommand } = require('./openclaw-control');
|
|
13
13
|
const { createOpencodeSession, deleteOpencodeSession, forwardChatMessage } = require('./opencode-service');
|
|
14
14
|
const { ServiceManager } = require('./service-manager');
|
|
@@ -128,21 +128,44 @@ class RongyunMessageHandler {
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
this.commandLock = true;
|
|
131
|
-
// 设置
|
|
131
|
+
// 设置 120 秒超时保护,防止命令永久卡住导致锁无法释放
|
|
132
|
+
// 启动命令可能需要较长时间(等待服务启动)
|
|
132
133
|
this.commandLockTimer = setTimeout(() => {
|
|
133
|
-
this.logWarn('[RongyunMessageHandler] 命令锁超时(
|
|
134
|
+
this.logWarn('[RongyunMessageHandler] 命令锁超时(120秒),自动释放');
|
|
134
135
|
this.commandLock = false;
|
|
135
136
|
this.commandLockTimer = null;
|
|
136
|
-
},
|
|
137
|
+
}, 120000);
|
|
137
138
|
|
|
138
139
|
try {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
140
|
+
// 先发送响应,再执行命令(避免前端超时)
|
|
141
|
+
// 启动/停止/重启命令是异步的,前端只需要知道命令已接收
|
|
142
|
+
const isAsyncCommand = [OpenClawCommandEnum.START, OpenClawCommandEnum.STOP, OpenClawCommandEnum.RESTART].includes(command);
|
|
143
|
+
|
|
144
|
+
if (isAsyncCommand) {
|
|
145
|
+
// 立即响应,告知前端命令已接收
|
|
142
146
|
await this.sendResponse(RongyunMessageTypeEnum.COMMAND_RESULT, {
|
|
143
|
-
|
|
144
|
-
command_id: commandId
|
|
147
|
+
command,
|
|
148
|
+
command_id: commandId,
|
|
149
|
+
status: 'success',
|
|
150
|
+
message: `${getCommandName(command)}命令已接收,正在执行...`
|
|
145
151
|
}, requestId, sourceId);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 执行命令(在后台异步执行,不阻塞响应)
|
|
155
|
+
// 使用 Promise 避免阻塞,让命令在后台执行
|
|
156
|
+
executeCommand(command, null, async (response) => {
|
|
157
|
+
if (!isAsyncCommand) {
|
|
158
|
+
// 同步命令立即响应
|
|
159
|
+
await this.sendResponse(RongyunMessageTypeEnum.COMMAND_RESULT, {
|
|
160
|
+
...response,
|
|
161
|
+
command_id: commandId
|
|
162
|
+
}, requestId, sourceId);
|
|
163
|
+
}
|
|
164
|
+
// 异步命令不在这里响应,因为已经提前响应了
|
|
165
|
+
// 但我们可以在这里记录执行结果
|
|
166
|
+
this.logInfo(`[RongyunMessageHandler] 命令执行完成: command=${command}, status=${response.status}, message=${response.message}`);
|
|
167
|
+
}).catch(err => {
|
|
168
|
+
this.logError(`[RongyunMessageHandler] 命令执行失败: ${err.message}`);
|
|
146
169
|
});
|
|
147
170
|
} catch (e) {
|
|
148
171
|
const msg = e instanceof Error ? e.message : String(e);
|