claw-subagent-service 0.0.89 → 0.0.90

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claw-subagent-service",
3
- "version": "0.0.89",
3
+ "version": "0.0.90",
4
4
  "description": "虾说智能助手",
5
5
  "main": "cli.js",
6
6
  "bin": {
@@ -85,31 +85,45 @@ async function manageWithServiceManager(command) {
85
85
 
86
86
  /**
87
87
  * 使用 ScriptExecutor 执行脚本(Docker 模式)
88
+ * @returns {Object} { result, output }
88
89
  */
89
90
  async function executeWithScript(command) {
90
91
  const executor = getExecutor();
91
92
  const scriptName = getScriptName(command);
92
93
 
93
94
  try {
94
- return await executor.executeWithStatus(command, scriptName);
95
+ const result = await executor.executeWithStatus(command, scriptName);
96
+ // ScriptExecutor 现在返回 { status, message, output }
97
+ return {
98
+ result: { status: result.status, message: result.message },
99
+ output: result.output || ''
100
+ };
95
101
  } catch (e) {
96
102
  const msg = e instanceof Error ? e.message : String(e);
97
103
  console.log(`[OpenClawControl] 脚本执行异常: ${msg}`);
98
104
  return {
99
- status: OpenClawServiceStatus.ERROR,
100
- message: `执行异常: ${msg}`
105
+ result: {
106
+ status: OpenClawServiceStatus.ERROR,
107
+ message: `执行异常: ${msg}`
108
+ },
109
+ output: ''
101
110
  };
102
111
  }
103
112
  }
104
113
 
105
114
  /**
106
115
  * 验证命令执行结果
116
+ *
117
+ * 注意:在 Docker 环境中,端口检查可能不可靠(服务可能绑定到特定网络接口)
118
+ * 因此,如果脚本输出明确指示成功,但端口检查失败,会给出警告但保留脚本结果
107
119
  */
108
- async function verifyCommandResult(command, result) {
120
+ async function verifyCommandResult(command, result, scriptOutput = '') {
109
121
  if (result.status === OpenClawServiceStatus.ERROR) {
110
122
  return result;
111
123
  }
112
124
 
125
+ const outputUpper = (scriptOutput || '').toUpperCase();
126
+
113
127
  if (command === OpenClawCommandEnum.STOP) {
114
128
  // 等待 3 秒后验证端口
115
129
  await new Promise(resolve => setTimeout(resolve, 3000));
@@ -117,6 +131,15 @@ async function verifyCommandResult(command, result) {
117
131
  console.log(`[OpenClawControl] 停止后端口状态: ${portStatus === 1 ? '运行中' : '未运行'}`);
118
132
 
119
133
  if (portStatus === 1) {
134
+ // 端口仍在监听,但检查脚本是否报告已停止
135
+ if (outputUpper.includes('SUCCESS') || outputUpper.includes('STOPPED')) {
136
+ console.warn(`[OpenClawControl] 警告: 端口仍在监听,但脚本报告成功。可能是僵尸进程或服务未正确停止。`);
137
+ // 仍然返回成功,但附带警告信息
138
+ return {
139
+ status: result.status,
140
+ message: result.message + ' (警告: 端口仍在监听)'
141
+ };
142
+ }
120
143
  return {
121
144
  status: OpenClawServiceStatus.ERROR,
122
145
  message: '停止失败: 服务仍在运行'
@@ -138,6 +161,15 @@ async function verifyCommandResult(command, result) {
138
161
  console.log(`[OpenClawControl] ${getCommandName(command)}后端口状态: ${portStatus === 1 ? '运行中' : '未运行'}`);
139
162
 
140
163
  if (portStatus === 0) {
164
+ // 端口未监听,但检查脚本是否报告成功(可能是服务绑定到其他接口)
165
+ if (outputUpper.includes('SUCCESS') || outputUpper.includes('ALREADY RUNNING')) {
166
+ console.warn(`[OpenClawControl] 警告: 端口检查失败,但脚本报告成功。服务可能绑定到其他网络接口。`);
167
+ // 信任脚本结果,但添加警告
168
+ return {
169
+ status: result.status,
170
+ message: result.message + ' (警告: 端口检查可能不准确)'
171
+ };
172
+ }
141
173
  return {
142
174
  status: OpenClawServiceStatus.ERROR,
143
175
  message: `${getCommandName(command)}失败: 服务未运行`
@@ -160,12 +192,15 @@ async function executeCommand(command, window, sendResponse) {
160
192
  }
161
193
 
162
194
  // 如果 ServiceManager 失败或不是 Linux/macOS,使用脚本方式
195
+ let scriptOutput = '';
163
196
  if (!result) {
164
- result = await executeWithScript(command);
197
+ const scriptResult = await executeWithScript(command);
198
+ result = scriptResult.result;
199
+ scriptOutput = scriptResult.output;
165
200
  }
166
201
 
167
- // 验证结果
168
- result = await verifyCommandResult(command, result);
202
+ // 验证结果(传递脚本输出用于后备检查)
203
+ result = await verifyCommandResult(command, result, scriptOutput);
169
204
 
170
205
  // 输出日志
171
206
  if (result.status === OpenClawServiceStatus.START_SUCCESS ||
@@ -1,6 +1,7 @@
1
1
  const net = require('net');
2
+ const os = require('os');
2
3
 
3
- function checkPortListening(port) {
4
+ function checkPortListening(port, host = '127.0.0.1') {
4
5
  return new Promise((resolve) => {
5
6
  const sock = new net.Socket();
6
7
  sock.setTimeout(3000);
@@ -16,16 +17,47 @@ function checkPortListening(port) {
16
17
  sock.destroy();
17
18
  resolve(false);
18
19
  });
19
- sock.connect(port, '127.0.0.1');
20
+ sock.connect(port, host);
20
21
  });
21
22
  }
22
23
 
24
+ /**
25
+ * 检查端口是否在所有网络接口上监听
26
+ * Docker 环境中,服务可能绑定到 0.0.0.0 而不是 127.0.0.1
27
+ */
28
+ async function checkPortOnAllInterfaces(port) {
29
+ // 先检查 localhost
30
+ const localhostListening = await checkPortListening(port, '127.0.0.1');
31
+ if (localhostListening) return true;
32
+
33
+ // 再检查 0.0.0.0(所有接口)
34
+ const allInterfacesListening = await checkPortListening(port, '0.0.0.0');
35
+ if (allInterfacesListening) return true;
36
+
37
+ // 获取所有网络接口并逐一检查
38
+ const interfaces = os.networkInterfaces();
39
+ for (const [name, addrs] of Object.entries(interfaces)) {
40
+ for (const addr of addrs) {
41
+ if (addr.family === 'IPv4' && !addr.internal) {
42
+ const listening = await checkPortListening(port, addr.address);
43
+ if (listening) {
44
+ console.log(`[PortChecker] 端口 ${port} 在 ${addr.address} (${name}) 上监听`);
45
+ return true;
46
+ }
47
+ }
48
+ }
49
+ }
50
+
51
+ return false;
52
+ }
53
+
23
54
  async function getOpenClawStatus(port = 18789) {
24
- const isListening = await checkPortListening(port);
55
+ const isListening = await checkPortOnAllInterfaces(port);
25
56
  return isListening ? 1 : 0;
26
57
  }
27
58
 
28
59
  module.exports = {
29
60
  checkPortListening,
61
+ checkPortOnAllInterfaces,
30
62
  getOpenClawStatus,
31
63
  };
@@ -103,11 +103,16 @@ class ScriptExecutor {
103
103
  console.log(`[ScriptExecutor] 停止脚本退出码非零(${exitCode}),返回错误`);
104
104
  return {
105
105
  status: OpenClawServiceStatus.ERROR,
106
- message: `停止失败: 脚本退出码 ${exitCode}`
106
+ message: `停止失败: 脚本退出码 ${exitCode}`,
107
+ output: fullOutput
107
108
  };
108
109
  }
109
110
 
110
- return result;
111
+ // 返回结果时附带原始输出
112
+ return {
113
+ ...result,
114
+ output: fullOutput
115
+ };
111
116
  } catch (e) {
112
117
  const msg = e instanceof Error ? e.message : String(e);
113
118
  return { status: OpenClawServiceStatus.ERROR, message: `执行异常: ${msg}` };