openclawsetup 2.8.4 → 2.8.5

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.
Files changed (2) hide show
  1. package/bin/cli.mjs +49 -5
  2. package/package.json +1 -1
package/bin/cli.mjs CHANGED
@@ -930,7 +930,7 @@ function probeGatewayStatus(cliName, timeout = STATUS_CMD_TIMEOUT_MS) {
930
930
 
931
931
  function getPortCheckOutput(port, timeout = PORT_CHECK_TIMEOUT_MS) {
932
932
  const cmd = platform() === 'win32'
933
- ? `netstat -ano | findstr :${port}`
933
+ ? `netstat -ano -p tcp | findstr LISTENING | findstr :${port}`
934
934
  : `lsof -nP -iTCP:${port} -sTCP:LISTEN 2>/dev/null || netstat -tlnp 2>/dev/null | grep :${port}`;
935
935
  return safeExec(cmd, { timeout });
936
936
  }
@@ -953,12 +953,33 @@ function isLikelyOpenClawProcess(output = '') {
953
953
  );
954
954
  }
955
955
 
956
+ function hasListeningState(output = '') {
957
+ if (!output) return false;
958
+ if (platform() !== 'win32') return Boolean(output.trim());
959
+ return output.toLowerCase().includes('listening');
960
+ }
961
+
956
962
  function gatewayHealthRequest(port, path = '/health') {
957
963
  const endpoint = `http://127.0.0.1:${port}${path}`;
958
964
  const curlCmd = `curl -sS --max-time 5 --connect-timeout 2 ${endpoint}`;
959
965
  return safeExec(curlCmd, { timeout: 7000 });
960
966
  }
961
967
 
968
+ function gatewayHttpStatusProbe(port, path = '/v1/responses') {
969
+ const endpoint = `http://127.0.0.1:${port}${path}`;
970
+ const cmd = `curl -sS -o /dev/null -w "%{http_code}" --max-time 5 --connect-timeout 2 ${endpoint}`;
971
+ const result = safeExec(cmd, { timeout: 7000 });
972
+ if (!result.ok || !result.output) {
973
+ return { ok: false, status: 0 };
974
+ }
975
+ const match = String(result.output).match(/\d{3}/);
976
+ const status = match ? Number(match[0]) : 0;
977
+ if (!Number.isInteger(status) || status <= 0) {
978
+ return { ok: false, status: 0 };
979
+ }
980
+ return { ok: true, status };
981
+ }
982
+
962
983
  function parseHealthOutput(raw = '') {
963
984
  if (!raw) return { healthy: false, detail: '空响应' };
964
985
 
@@ -1280,6 +1301,7 @@ async function runOfficialDoctor(cliName, autoFix = false, strongMode = false) {
1280
1301
 
1281
1302
  async function verifyGatewayApi(port, cliName, autoFix = false, strongMode = false) {
1282
1303
  const paths = ['/health', '/api/health', '/status'];
1304
+ const probePaths = ['/v1/responses', '/v1/models', '/'];
1283
1305
 
1284
1306
  for (const path of paths) {
1285
1307
  const healthResult = gatewayHealthRequest(port, path);
@@ -1290,6 +1312,14 @@ async function verifyGatewayApi(port, cliName, autoFix = false, strongMode = fal
1290
1312
  }
1291
1313
  }
1292
1314
 
1315
+ for (const path of probePaths) {
1316
+ const probe = gatewayHttpStatusProbe(port, path);
1317
+ if (!probe.ok) continue;
1318
+ if (probe.status >= 200 && probe.status < 500) {
1319
+ return { ok: true, issue: null };
1320
+ }
1321
+ }
1322
+
1293
1323
  const issue = summarizeIssue(
1294
1324
  'error',
1295
1325
  'API 无响应',
@@ -1318,6 +1348,14 @@ async function verifyGatewayApi(port, cliName, autoFix = false, strongMode = fal
1318
1348
  }
1319
1349
  }
1320
1350
 
1351
+ for (const path of probePaths) {
1352
+ const probe = gatewayHttpStatusProbe(port, path);
1353
+ if (!probe.ok) continue;
1354
+ if (probe.status >= 200 && probe.status < 500) {
1355
+ return { ok: true, issue: null, fixed: true };
1356
+ }
1357
+ }
1358
+
1321
1359
  return { ok: false, issue, fixed: false };
1322
1360
  }
1323
1361
 
@@ -2135,11 +2173,12 @@ async function runHealthCheck(cliName, autoFix = false, strongMode = false) {
2135
2173
  const statusPortResult = getPortCheckOutput(portForStatus, PORT_CHECK_TIMEOUT_MS);
2136
2174
  const statusPortListening = Boolean(statusPortResult.ok && statusPortResult.output);
2137
2175
 
2138
- if (statusState === 'running' || (statusState !== 'running' && statusPortListening)) {
2176
+ const canUsePortFallback = statusState === 'unknown' || statusProbe.timedOut;
2177
+ if (statusState === 'running' || (canUsePortFallback && statusPortListening)) {
2139
2178
  log.success('Gateway 进程正在运行');
2140
2179
  if (statusProbe.timedOut) {
2141
2180
  log.hint('状态命令超时,已按端口监听判定为运行中');
2142
- } else if (statusState !== 'running' && statusPortListening) {
2181
+ } else if (canUsePortFallback && statusPortListening) {
2143
2182
  log.hint('状态命令返回非运行,但端口可访问(兼容判定)');
2144
2183
  }
2145
2184
  } else {
@@ -2175,7 +2214,12 @@ async function runHealthCheck(cliName, autoFix = false, strongMode = false) {
2175
2214
 
2176
2215
  const portResult = getPortCheckOutput(port);
2177
2216
  if (portResult.ok && portResult.output) {
2178
- if (isLikelyOpenClawProcess(portResult.output)) {
2217
+ const listening = hasListeningState(portResult.output);
2218
+ const winLikelyGateway = platform() === 'win32'
2219
+ && listening
2220
+ && (statusState === 'running' || statusProbe.timedOut || statusState === 'unknown');
2221
+
2222
+ if (winLikelyGateway || isLikelyOpenClawProcess(portResult.output)) {
2179
2223
  log.success(`端口 ${port} 正在监听`);
2180
2224
  portHealthy = true;
2181
2225
  } else {
@@ -2220,7 +2264,7 @@ async function runHealthCheck(cliName, autoFix = false, strongMode = false) {
2220
2264
  if (recovered.ok) {
2221
2265
  await sleep(2500);
2222
2266
  const recheck = getPortCheckOutput(port);
2223
- if (recheck.ok && recheck.output) {
2267
+ if (recheck.ok && recheck.output && hasListeningState(recheck.output)) {
2224
2268
  log.success(`端口 ${port} 已恢复监听`);
2225
2269
  fixed.push(`端口监听已恢复(${port})`);
2226
2270
  portHealthy = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclawsetup",
3
- "version": "2.8.4",
3
+ "version": "2.8.5",
4
4
  "description": "OpenClaw 安装向导 - 智能安装、诊断、自动修复",
5
5
  "type": "module",
6
6
  "bin": {