openclawsetup 2.8.9 → 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 +93 -40
- package/package.json +1 -1
package/bin/cli.mjs
CHANGED
|
@@ -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());
|
|
@@ -2573,61 +2643,44 @@ async function showStatusInfo(cliName) {
|
|
|
2573
2643
|
const dashboardUrl = `http://127.0.0.1:${port}/?token=${token}`;
|
|
2574
2644
|
|
|
2575
2645
|
console.log(colors.bold(colors.cyan('\n📊 OpenClaw 状态信息\n')));
|
|
2576
|
-
console.log(colors.gray(' …
|
|
2577
|
-
|
|
2578
|
-
// 服务状态(兼容不同 CLI 版本,避免 Windows 下误判)
|
|
2579
|
-
const statusAttempts = [
|
|
2580
|
-
{ cmd: `${cliName} status`, label: 'status' },
|
|
2581
|
-
{ cmd: `${cliName} gateway status`, label: 'gateway status' },
|
|
2582
|
-
];
|
|
2583
|
-
let statusState = 'unknown';
|
|
2584
|
-
let statusOutput = '';
|
|
2585
|
-
let statusTimedOut = false;
|
|
2586
|
-
|
|
2587
|
-
for (const attempt of statusAttempts) {
|
|
2588
|
-
const statusResult = safeExec(attempt.cmd, { timeout: STATUS_CMD_TIMEOUT_MS });
|
|
2589
|
-
if (!statusResult.ok && /timed out|etimedout|SIGTERM|killed/i.test(`${statusResult.error || ''} ${statusResult.stderr || ''}`)) {
|
|
2590
|
-
statusTimedOut = true;
|
|
2591
|
-
continue;
|
|
2592
|
-
}
|
|
2593
|
-
if (!statusResult.ok || !statusResult.output) continue;
|
|
2594
|
-
statusOutput = statusResult.output;
|
|
2595
|
-
const parsed = parseStatusOutput(statusResult.output);
|
|
2596
|
-
if (parsed === 'running') {
|
|
2597
|
-
statusState = 'running';
|
|
2598
|
-
break;
|
|
2599
|
-
}
|
|
2600
|
-
if (parsed === 'stopped') {
|
|
2601
|
-
statusState = 'stopped';
|
|
2602
|
-
}
|
|
2603
|
-
}
|
|
2646
|
+
console.log(colors.gray(' … 正在检查服务状态...'));
|
|
2604
2647
|
|
|
2605
|
-
//
|
|
2648
|
+
// 1. 直接通过端口检测进程(不依赖 openclaw status 命令)
|
|
2649
|
+
const processInfo = detectGatewayProcess(port);
|
|
2606
2650
|
const portResult = getPortCheckOutput(port, PORT_CHECK_TIMEOUT_MS);
|
|
2607
2651
|
const portListening = Boolean(portResult.ok && portResult.output);
|
|
2608
2652
|
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
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;
|
|
2614
2658
|
}
|
|
2615
2659
|
|
|
2616
|
-
|
|
2660
|
+
// 3. 综合判断并显示
|
|
2661
|
+
if (processInfo.found && processInfo.isOpenClaw) {
|
|
2617
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;
|
|
2618
2672
|
} else if (portListening) {
|
|
2619
|
-
//
|
|
2673
|
+
// 端口在监听但无法获取进程详情(权限不足等)
|
|
2674
|
+
console.log(colors.green(' ✓ Gateway 服务正在运行'));
|
|
2675
|
+
} else if (statusState === 'running') {
|
|
2620
2676
|
console.log(colors.green(' ✓ Gateway 服务正在运行'));
|
|
2621
2677
|
} else {
|
|
2622
2678
|
console.log(colors.red(' ✗ Gateway 服务未运行'));
|
|
2623
|
-
if (statusOutput) {
|
|
2624
|
-
console.log(colors.gray(` 状态输出: ${statusOutput.split('\n')[0].slice(0, 100)}`));
|
|
2625
|
-
}
|
|
2626
2679
|
console.log(colors.yellow(' → 请先选择「检查修复」自动修复此问题\n'));
|
|
2627
2680
|
return;
|
|
2628
2681
|
}
|
|
2629
2682
|
|
|
2630
|
-
if (
|
|
2683
|
+
if (portListening) {
|
|
2631
2684
|
console.log(colors.green(` ✓ 端口 ${port} 正在监听`));
|
|
2632
2685
|
} else {
|
|
2633
2686
|
console.log(colors.red(` ✗ 端口 ${port} 未监听`));
|