openclawsetup 2.8.8 → 2.8.10
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 +95 -47
- package/package.json +1 -1
package/bin/cli.mjs
CHANGED
|
@@ -83,7 +83,7 @@ const log = {
|
|
|
83
83
|
|
|
84
84
|
const DEFAULT_GATEWAY_PORT = 18789;
|
|
85
85
|
const STRONG_FIX_MAX_PASSES = 3;
|
|
86
|
-
const STATUS_CMD_TIMEOUT_MS = platform() === 'win32' ?
|
|
86
|
+
const STATUS_CMD_TIMEOUT_MS = platform() === 'win32' ? 15000 : 10000;
|
|
87
87
|
const PORT_CHECK_TIMEOUT_MS = platform() === 'win32' ? 6000 : 4000;
|
|
88
88
|
const MODEL_CHAT_TIMEOUT_MS = platform() === 'win32' ? 25000 : 18000;
|
|
89
89
|
const STRONG_PORT_CANDIDATES = [
|
|
@@ -953,6 +953,76 @@ function isLikelyOpenClawProcess(output = '') {
|
|
|
953
953
|
);
|
|
954
954
|
}
|
|
955
955
|
|
|
956
|
+
/**
|
|
957
|
+
* 通过端口直接检测 Gateway 进程信息(不依赖 openclaw status 命令)
|
|
958
|
+
* 返回 { found, pid, processName, cmdline, isOpenClaw }
|
|
959
|
+
*/
|
|
960
|
+
function detectGatewayProcess(port) {
|
|
961
|
+
const result = { found: false, pid: null, processName: '', cmdline: '', isOpenClaw: false };
|
|
962
|
+
|
|
963
|
+
if (platform() === 'win32') {
|
|
964
|
+
// Windows: netstat 找 PID,再用 wmic 查进程详情
|
|
965
|
+
const netstat = safeExec(`netstat -ano -p tcp | findstr LISTENING | findstr :${port}`, { timeout: 8000 });
|
|
966
|
+
if (!netstat.ok || !netstat.output) return result;
|
|
967
|
+
|
|
968
|
+
// 提取 PID(netstat 输出最后一列是 PID)
|
|
969
|
+
const pidMatch = netstat.output.match(/LISTENING\s+(\d+)/);
|
|
970
|
+
if (!pidMatch) return result;
|
|
971
|
+
result.pid = pidMatch[1];
|
|
972
|
+
result.found = true;
|
|
973
|
+
|
|
974
|
+
// 用 wmic 获取进程命令行
|
|
975
|
+
const wmic = safeExec(`wmic process where "ProcessId=${result.pid}" get CommandLine,Name /format:list`, { timeout: 5000 });
|
|
976
|
+
if (wmic.ok && wmic.output) {
|
|
977
|
+
const nameMatch = wmic.output.match(/Name=(.+)/i);
|
|
978
|
+
const cmdMatch = wmic.output.match(/CommandLine=(.+)/i);
|
|
979
|
+
result.processName = nameMatch ? nameMatch[1].trim() : '';
|
|
980
|
+
result.cmdline = cmdMatch ? cmdMatch[1].trim() : '';
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
// wmic 可能不可用(新版 Windows),回退用 tasklist
|
|
984
|
+
if (!result.processName) {
|
|
985
|
+
const tasklist = safeExec(`tasklist /FI "PID eq ${result.pid}" /FO CSV /NH`, { timeout: 5000 });
|
|
986
|
+
if (tasklist.ok && tasklist.output) {
|
|
987
|
+
const parts = tasklist.output.split(',');
|
|
988
|
+
if (parts.length > 0) {
|
|
989
|
+
result.processName = parts[0].replace(/"/g, '').trim();
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
} else {
|
|
994
|
+
// Linux/macOS: lsof 找 PID 和进程名
|
|
995
|
+
const lsof = safeExec(`lsof -nP -iTCP:${port} -sTCP:LISTEN -F pcn 2>/dev/null`, { timeout: 5000 });
|
|
996
|
+
if (lsof.ok && lsof.output) {
|
|
997
|
+
const pidMatch = lsof.output.match(/p(\d+)/);
|
|
998
|
+
const nameMatch = lsof.output.match(/c(.+)/);
|
|
999
|
+
if (pidMatch) {
|
|
1000
|
+
result.pid = pidMatch[1];
|
|
1001
|
+
result.found = true;
|
|
1002
|
+
result.processName = nameMatch ? nameMatch[1].trim() : '';
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
// 获取完整命令行
|
|
1007
|
+
if (result.pid) {
|
|
1008
|
+
const cmdline = safeExec(`cat /proc/${result.pid}/cmdline 2>/dev/null | tr '\\0' ' ' || ps -p ${result.pid} -o args= 2>/dev/null`, { timeout: 3000 });
|
|
1009
|
+
if (cmdline.ok && cmdline.output) {
|
|
1010
|
+
result.cmdline = cmdline.output.trim();
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
// 判断是否是 OpenClaw 进程
|
|
1016
|
+
const combined = `${result.processName} ${result.cmdline}`.toLowerCase();
|
|
1017
|
+
result.isOpenClaw = combined.includes('openclaw') || combined.includes('clawdbot') || combined.includes('moltbot');
|
|
1018
|
+
// node 进程运行 gateway 也算
|
|
1019
|
+
if (!result.isOpenClaw && combined.includes('node') && combined.includes('gateway')) {
|
|
1020
|
+
result.isOpenClaw = true;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
return result;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
956
1026
|
function hasListeningState(output = '') {
|
|
957
1027
|
if (!output) return false;
|
|
958
1028
|
if (platform() !== 'win32') return Boolean(output.trim());
|
|
@@ -2233,11 +2303,6 @@ async function runHealthCheck(cliName, autoFix = false, strongMode = false) {
|
|
|
2233
2303
|
const canUsePortFallback = statusState === 'unknown' || statusProbe.timedOut;
|
|
2234
2304
|
if (statusState === 'running' || (canUsePortFallback && statusPortListening)) {
|
|
2235
2305
|
log.success('Gateway 进程正在运行');
|
|
2236
|
-
if (statusProbe.timedOut) {
|
|
2237
|
-
log.hint('状态命令超时,已按端口监听判定为运行中');
|
|
2238
|
-
} else if (canUsePortFallback && statusPortListening) {
|
|
2239
|
-
log.hint('状态命令返回非运行,但端口可访问(兼容判定)');
|
|
2240
|
-
}
|
|
2241
2306
|
} else {
|
|
2242
2307
|
const issue = summarizeIssue(
|
|
2243
2308
|
'error',
|
|
@@ -2578,61 +2643,44 @@ async function showStatusInfo(cliName) {
|
|
|
2578
2643
|
const dashboardUrl = `http://127.0.0.1:${port}/?token=${token}`;
|
|
2579
2644
|
|
|
2580
2645
|
console.log(colors.bold(colors.cyan('\n📊 OpenClaw 状态信息\n')));
|
|
2581
|
-
console.log(colors.gray(' …
|
|
2646
|
+
console.log(colors.gray(' … 正在检查服务状态...'));
|
|
2582
2647
|
|
|
2583
|
-
//
|
|
2584
|
-
const
|
|
2585
|
-
{ cmd: `${cliName} status`, label: 'status' },
|
|
2586
|
-
{ cmd: `${cliName} gateway status`, label: 'gateway status' },
|
|
2587
|
-
];
|
|
2588
|
-
let statusState = 'unknown';
|
|
2589
|
-
let statusOutput = '';
|
|
2590
|
-
let statusTimedOut = false;
|
|
2591
|
-
|
|
2592
|
-
for (const attempt of statusAttempts) {
|
|
2593
|
-
const statusResult = safeExec(attempt.cmd, { timeout: STATUS_CMD_TIMEOUT_MS });
|
|
2594
|
-
if (!statusResult.ok && /timed out|etimedout|SIGTERM|killed/i.test(`${statusResult.error || ''} ${statusResult.stderr || ''}`)) {
|
|
2595
|
-
statusTimedOut = true;
|
|
2596
|
-
continue;
|
|
2597
|
-
}
|
|
2598
|
-
if (!statusResult.ok || !statusResult.output) continue;
|
|
2599
|
-
statusOutput = statusResult.output;
|
|
2600
|
-
const parsed = parseStatusOutput(statusResult.output);
|
|
2601
|
-
if (parsed === 'running') {
|
|
2602
|
-
statusState = 'running';
|
|
2603
|
-
break;
|
|
2604
|
-
}
|
|
2605
|
-
if (parsed === 'stopped') {
|
|
2606
|
-
statusState = 'stopped';
|
|
2607
|
-
}
|
|
2608
|
-
}
|
|
2609
|
-
|
|
2610
|
-
// 端口检查(作为状态命令兜底)
|
|
2648
|
+
// 1. 直接通过端口检测进程(不依赖 openclaw status 命令)
|
|
2649
|
+
const processInfo = detectGatewayProcess(port);
|
|
2611
2650
|
const portResult = getPortCheckOutput(port, PORT_CHECK_TIMEOUT_MS);
|
|
2612
2651
|
const portListening = Boolean(portResult.ok && portResult.output);
|
|
2613
2652
|
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2653
|
+
// 2. 如果直接检测没结果,再尝试 openclaw status 命令
|
|
2654
|
+
let statusState = 'unknown';
|
|
2655
|
+
if (!processInfo.found && !portListening) {
|
|
2656
|
+
const statusProbe = probeGatewayStatus(cliName, STATUS_CMD_TIMEOUT_MS);
|
|
2657
|
+
statusState = statusProbe.state;
|
|
2619
2658
|
}
|
|
2620
2659
|
|
|
2621
|
-
|
|
2660
|
+
// 3. 综合判断并显示
|
|
2661
|
+
if (processInfo.found && processInfo.isOpenClaw) {
|
|
2622
2662
|
console.log(colors.green(' ✓ Gateway 服务正在运行'));
|
|
2663
|
+
console.log(colors.gray(` 进程: ${processInfo.processName || 'node'} (PID ${processInfo.pid})`));
|
|
2664
|
+
} else if (processInfo.found && !processInfo.isOpenClaw) {
|
|
2665
|
+
console.log(colors.yellow(` ⚠ 端口 ${port} 被其他进程占用`));
|
|
2666
|
+
console.log(colors.gray(` 进程: ${processInfo.processName || '未知'} (PID ${processInfo.pid})`));
|
|
2667
|
+
if (processInfo.cmdline) {
|
|
2668
|
+
console.log(colors.gray(` 命令: ${processInfo.cmdline.substring(0, 120)}`));
|
|
2669
|
+
}
|
|
2670
|
+
console.log(colors.yellow(' → 请先选择「检查修复」解决端口冲突\n'));
|
|
2671
|
+
return;
|
|
2623
2672
|
} else if (portListening) {
|
|
2624
|
-
|
|
2625
|
-
console.log(colors.
|
|
2673
|
+
// 端口在监听但无法获取进程详情(权限不足等)
|
|
2674
|
+
console.log(colors.green(' ✓ Gateway 服务正在运行'));
|
|
2675
|
+
} else if (statusState === 'running') {
|
|
2676
|
+
console.log(colors.green(' ✓ Gateway 服务正在运行'));
|
|
2626
2677
|
} else {
|
|
2627
2678
|
console.log(colors.red(' ✗ Gateway 服务未运行'));
|
|
2628
|
-
if (statusOutput) {
|
|
2629
|
-
console.log(colors.gray(` 状态输出: ${statusOutput.split('\n')[0].slice(0, 100)}`));
|
|
2630
|
-
}
|
|
2631
2679
|
console.log(colors.yellow(' → 请先选择「检查修复」自动修复此问题\n'));
|
|
2632
2680
|
return;
|
|
2633
2681
|
}
|
|
2634
2682
|
|
|
2635
|
-
if (
|
|
2683
|
+
if (portListening) {
|
|
2636
2684
|
console.log(colors.green(` ✓ 端口 ${port} 正在监听`));
|
|
2637
2685
|
} else {
|
|
2638
2686
|
console.log(colors.red(` ✗ 端口 ${port} 未监听`));
|