openclawsetup 2.8.4 → 2.8.6
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/bin/cli.mjs +109 -5
- 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
|
|
|
@@ -1921,6 +1959,63 @@ async function updateOpenClaw(cliName) {
|
|
|
1921
1959
|
}
|
|
1922
1960
|
}
|
|
1923
1961
|
|
|
1962
|
+
// ============ 安装后 Gateway 验证 ============
|
|
1963
|
+
|
|
1964
|
+
async function verifyAndStartGateway(cliName) {
|
|
1965
|
+
const config = getConfigInfo();
|
|
1966
|
+
const port = config.port || DEFAULT_GATEWAY_PORT;
|
|
1967
|
+
|
|
1968
|
+
console.log(colors.cyan('\n验证 Gateway 服务...'));
|
|
1969
|
+
|
|
1970
|
+
// 等待 Gateway 启动(onboard 可能刚启动 daemon,需要时间)
|
|
1971
|
+
await sleep(3000);
|
|
1972
|
+
|
|
1973
|
+
// 检查端口是否在监听
|
|
1974
|
+
const portCheck = getPortCheckOutput(port);
|
|
1975
|
+
if (portCheck.ok && hasListeningState(portCheck.output)) {
|
|
1976
|
+
// 端口在监听,再验证 health
|
|
1977
|
+
const health = gatewayHealthRequest(port);
|
|
1978
|
+
if (health.ok) {
|
|
1979
|
+
log.success('Gateway 运行正常');
|
|
1980
|
+
return;
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
// Gateway 未启动,尝试手动启动
|
|
1985
|
+
log.warn('Gateway 未就绪,正在尝试启动...');
|
|
1986
|
+
|
|
1987
|
+
const startResult = await ensureGatewayRunning(cliName, 'start');
|
|
1988
|
+
if (startResult.ok) {
|
|
1989
|
+
// 再次验证端口
|
|
1990
|
+
await sleep(2000);
|
|
1991
|
+
const recheck = getPortCheckOutput(port);
|
|
1992
|
+
if (recheck.ok && hasListeningState(recheck.output)) {
|
|
1993
|
+
log.success('Gateway 已启动');
|
|
1994
|
+
return;
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
// 仍然失败,尝试 restart
|
|
1999
|
+
log.warn('启动失败,尝试重启...');
|
|
2000
|
+
const restartResult = await ensureGatewayRunning(cliName, 'restart');
|
|
2001
|
+
if (restartResult.ok) {
|
|
2002
|
+
await sleep(2000);
|
|
2003
|
+
const recheck2 = getPortCheckOutput(port);
|
|
2004
|
+
if (recheck2.ok && hasListeningState(recheck2.output)) {
|
|
2005
|
+
log.success('Gateway 已重启成功');
|
|
2006
|
+
return;
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
// 所有尝试失败
|
|
2011
|
+
log.error(`Gateway 未能在端口 ${port} 上启动`);
|
|
2012
|
+
console.log(colors.yellow('\n请手动排查:'));
|
|
2013
|
+
console.log(` 1. 运行: ${colors.green(`${cliName} gateway start`)}`);
|
|
2014
|
+
console.log(` 2. 查看日志: ${colors.green(`${cliName} gateway logs`)}`);
|
|
2015
|
+
console.log(` 3. 检查端口: ${colors.green(`${cliName} status`)}`);
|
|
2016
|
+
console.log(` 4. 运行诊断: ${colors.green(`npx openclawsetup@latest --fix`)}`);
|
|
2017
|
+
}
|
|
2018
|
+
|
|
1924
2019
|
// ============ 完成信息 ============
|
|
1925
2020
|
|
|
1926
2021
|
function showCompletionInfo(cliName) {
|
|
@@ -2135,11 +2230,12 @@ async function runHealthCheck(cliName, autoFix = false, strongMode = false) {
|
|
|
2135
2230
|
const statusPortResult = getPortCheckOutput(portForStatus, PORT_CHECK_TIMEOUT_MS);
|
|
2136
2231
|
const statusPortListening = Boolean(statusPortResult.ok && statusPortResult.output);
|
|
2137
2232
|
|
|
2138
|
-
|
|
2233
|
+
const canUsePortFallback = statusState === 'unknown' || statusProbe.timedOut;
|
|
2234
|
+
if (statusState === 'running' || (canUsePortFallback && statusPortListening)) {
|
|
2139
2235
|
log.success('Gateway 进程正在运行');
|
|
2140
2236
|
if (statusProbe.timedOut) {
|
|
2141
2237
|
log.hint('状态命令超时,已按端口监听判定为运行中');
|
|
2142
|
-
} else if (
|
|
2238
|
+
} else if (canUsePortFallback && statusPortListening) {
|
|
2143
2239
|
log.hint('状态命令返回非运行,但端口可访问(兼容判定)');
|
|
2144
2240
|
}
|
|
2145
2241
|
} else {
|
|
@@ -2175,7 +2271,12 @@ async function runHealthCheck(cliName, autoFix = false, strongMode = false) {
|
|
|
2175
2271
|
|
|
2176
2272
|
const portResult = getPortCheckOutput(port);
|
|
2177
2273
|
if (portResult.ok && portResult.output) {
|
|
2178
|
-
|
|
2274
|
+
const listening = hasListeningState(portResult.output);
|
|
2275
|
+
const winLikelyGateway = platform() === 'win32'
|
|
2276
|
+
&& listening
|
|
2277
|
+
&& (statusState === 'running' || statusProbe.timedOut || statusState === 'unknown');
|
|
2278
|
+
|
|
2279
|
+
if (winLikelyGateway || isLikelyOpenClawProcess(portResult.output)) {
|
|
2179
2280
|
log.success(`端口 ${port} 正在监听`);
|
|
2180
2281
|
portHealthy = true;
|
|
2181
2282
|
} else {
|
|
@@ -2220,7 +2321,7 @@ async function runHealthCheck(cliName, autoFix = false, strongMode = false) {
|
|
|
2220
2321
|
if (recovered.ok) {
|
|
2221
2322
|
await sleep(2500);
|
|
2222
2323
|
const recheck = getPortCheckOutput(port);
|
|
2223
|
-
if (recheck.ok && recheck.output) {
|
|
2324
|
+
if (recheck.ok && recheck.output && hasListeningState(recheck.output)) {
|
|
2224
2325
|
log.success(`端口 ${port} 已恢复监听`);
|
|
2225
2326
|
fixed.push(`端口监听已恢复(${port})`);
|
|
2226
2327
|
portHealthy = true;
|
|
@@ -2836,6 +2937,9 @@ async function main() {
|
|
|
2836
2937
|
// 运行 onboard
|
|
2837
2938
|
await runOnboard(cliName);
|
|
2838
2939
|
|
|
2940
|
+
// 验证 Gateway 是否启动,未启动则尝试启动
|
|
2941
|
+
await verifyAndStartGateway(cliName);
|
|
2942
|
+
|
|
2839
2943
|
// 显示完成信息
|
|
2840
2944
|
showCompletionInfo(cliName);
|
|
2841
2945
|
}
|