openclawsetup 2.1.5 → 2.2.0

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 +247 -9
  2. package/package.json +1 -1
package/bin/cli.mjs CHANGED
@@ -78,6 +78,7 @@ function parseArgs() {
78
78
  update: args.includes('--update'),
79
79
  reinstall: args.includes('--reinstall'),
80
80
  uninstall: args.includes('--uninstall'),
81
+ check: args.includes('--check'),
81
82
  manual: args.includes('--manual'),
82
83
  auto: args.includes('--auto'),
83
84
  withModel: args.includes('--with-model'),
@@ -91,7 +92,8 @@ function showHelp() {
91
92
  ${colors.bold('OpenClaw 安装向导')}
92
93
 
93
94
  ${colors.cyan('用法:')}
94
- npx openclawsetup 带中文指引的安装
95
+ npx openclawsetup 交互式菜单(已安装)/ 安装向导(未安装)
96
+ npx openclawsetup --check 检查配置和服务状态
95
97
  npx openclawsetup --update 更新已安装的 OpenClaw
96
98
  npx openclawsetup --reinstall 卸载后重新安装
97
99
  npx openclawsetup --uninstall 卸载 OpenClaw
@@ -866,6 +868,243 @@ async function uninstallOpenClaw(existing) {
866
868
  log.success('卸载完成');
867
869
  }
868
870
 
871
+ // ============ 健康检查 ============
872
+
873
+ async function runHealthCheck(cliName) {
874
+ console.log(colors.bold(colors.cyan('\n🔍 OpenClaw 健康检查\n')));
875
+
876
+ const issues = [];
877
+ const config = getConfigInfo();
878
+
879
+ // 1. 检查配置文件
880
+ console.log(colors.cyan('检查配置文件...'));
881
+ if (!config.configPath || !existsSync(config.configPath)) {
882
+ issues.push({
883
+ level: 'error',
884
+ title: '配置文件不存在',
885
+ detail: '未找到 openclaw.json 配置文件',
886
+ solution: '运行 openclaw onboard 重新配置',
887
+ });
888
+ } else {
889
+ try {
890
+ const raw = readFileSync(config.configPath, 'utf8');
891
+ JSON.parse(raw);
892
+ log.success('配置文件格式正确');
893
+ } catch (e) {
894
+ issues.push({
895
+ level: 'error',
896
+ title: '配置文件 JSON 格式错误',
897
+ detail: `解析失败: ${e.message}`,
898
+ solution: '检查 ~/.openclaw/openclaw.json 的 JSON 语法,或删除后重新运行 openclaw onboard',
899
+ });
900
+ }
901
+ }
902
+
903
+ // 2. 检查 Gateway 进程
904
+ console.log(colors.cyan('检查 Gateway 进程...'));
905
+ const statusResult = safeExec(`${cliName} status`);
906
+ if (statusResult.ok) {
907
+ const output = statusResult.output.toLowerCase();
908
+ if (output.includes('running') || output.includes('active')) {
909
+ log.success('Gateway 进程正在运行');
910
+ } else if (output.includes('stopped') || output.includes('inactive') || output.includes('not running')) {
911
+ issues.push({
912
+ level: 'error',
913
+ title: 'Gateway 未运行',
914
+ detail: 'Gateway 服务已停止',
915
+ solution: `运行 ${cliName} gateway start 启动服务`,
916
+ });
917
+ }
918
+ } else {
919
+ issues.push({
920
+ level: 'warning',
921
+ title: '无法获取 Gateway 状态',
922
+ detail: statusResult.error || '状态检查失败',
923
+ solution: `尝试运行 ${cliName} status 查看详情`,
924
+ });
925
+ }
926
+
927
+ // 3. 检查端口监听
928
+ console.log(colors.cyan('检查端口监听...'));
929
+ const port = config.port || 18789;
930
+ const portCheckCmd = platform() === 'win32'
931
+ ? `netstat -an | findstr :${port}`
932
+ : `lsof -i :${port} 2>/dev/null || netstat -tlnp 2>/dev/null | grep :${port}`;
933
+ const portResult = safeExec(portCheckCmd);
934
+
935
+ if (portResult.ok && portResult.output) {
936
+ log.success(`端口 ${port} 正在监听`);
937
+ } else {
938
+ issues.push({
939
+ level: 'error',
940
+ title: `端口 ${port} 未监听`,
941
+ detail: 'Gateway 端口未开放,服务可能未正常启动',
942
+ solution: `1. 运行 ${cliName} gateway restart\n 2. 检查是否有其他程序占用端口 ${port}`,
943
+ });
944
+ }
945
+
946
+ // 4. 检查 API 健康
947
+ console.log(colors.cyan('检查 API 健康状态...'));
948
+ const healthResult = safeExec(`curl -s --connect-timeout 3 http://127.0.0.1:${port}/health`);
949
+ if (healthResult.ok && healthResult.output) {
950
+ try {
951
+ const health = JSON.parse(healthResult.output);
952
+ if (health.status === 'ok' || health.healthy) {
953
+ log.success('API 健康检查通过');
954
+ } else {
955
+ issues.push({
956
+ level: 'warning',
957
+ title: 'API 健康状态异常',
958
+ detail: JSON.stringify(health),
959
+ solution: `运行 ${cliName} gateway logs 查看日志`,
960
+ });
961
+ }
962
+ } catch {
963
+ if (healthResult.output.includes('ok') || healthResult.output.includes('healthy')) {
964
+ log.success('API 健康检查通过');
965
+ } else {
966
+ log.warn('API 返回非标准格式');
967
+ }
968
+ }
969
+ } else {
970
+ issues.push({
971
+ level: 'error',
972
+ title: 'API 无响应',
973
+ detail: '无法连接到 Gateway API',
974
+ solution: `1. 确认 Gateway 正在运行: ${cliName} status\n 2. 重启服务: ${cliName} gateway restart`,
975
+ });
976
+ }
977
+
978
+ // 5. 检查模型配置
979
+ console.log(colors.cyan('检查模型配置...'));
980
+ if (config.raw) {
981
+ const hasModels = config.raw.includes('"models"') || config.raw.includes('"providers"');
982
+ const hasApiKey = config.raw.includes('"apiKey"') || config.raw.includes('"api_key"');
983
+ if (!hasModels && !hasApiKey) {
984
+ issues.push({
985
+ level: 'warning',
986
+ title: '未配置 AI 模型',
987
+ detail: '配置文件中未找到模型或 API Key 配置',
988
+ solution: '运行 npx openclawapi@latest 配置模型',
989
+ });
990
+ } else {
991
+ log.success('已配置模型');
992
+ }
993
+ }
994
+
995
+ // 6. 运行官方诊断
996
+ console.log(colors.cyan('运行官方诊断...'));
997
+ const doctorResult = safeExec(`${cliName} doctor`);
998
+ if (doctorResult.ok) {
999
+ const output = doctorResult.output.toLowerCase();
1000
+ if (output.includes('error') || output.includes('fail') || output.includes('问题')) {
1001
+ issues.push({
1002
+ level: 'warning',
1003
+ title: '官方诊断发现问题',
1004
+ detail: doctorResult.output.slice(0, 200),
1005
+ solution: `运行 ${cliName} doctor 查看完整诊断`,
1006
+ });
1007
+ } else {
1008
+ log.success('官方诊断通过');
1009
+ }
1010
+ }
1011
+
1012
+ // 输出结果
1013
+ console.log('\n' + '='.repeat(50));
1014
+ if (issues.length === 0) {
1015
+ console.log(colors.bold(colors.green('✅ 所有检查通过,OpenClaw 运行正常!')));
1016
+ } else {
1017
+ console.log(colors.bold(colors.yellow(`⚠ 发现 ${issues.length} 个问题:`)));
1018
+ console.log('='.repeat(50));
1019
+
1020
+ issues.forEach((issue, i) => {
1021
+ const icon = issue.level === 'error' ? colors.red('❌') : colors.yellow('⚠');
1022
+ console.log(`\n${icon} ${colors.bold(`问题 ${i + 1}: ${issue.title}`)}`);
1023
+ console.log(colors.gray(` ${issue.detail}`));
1024
+ console.log(colors.cyan(` 解决方案: ${issue.solution}`));
1025
+ });
1026
+ }
1027
+ console.log('');
1028
+ }
1029
+
1030
+ // ============ 交互式菜单 ============
1031
+
1032
+ async function showInteractiveMenu(existing) {
1033
+ const cliName = existing.name || 'openclaw';
1034
+
1035
+ while (true) {
1036
+ console.log(colors.bold(colors.cyan('\n' + '='.repeat(50))));
1037
+ console.log(colors.bold(colors.cyan(' OpenClaw 管理菜单')));
1038
+ console.log(colors.bold(colors.cyan('='.repeat(50))));
1039
+
1040
+ showDashboardAccessInfo();
1041
+
1042
+ console.log(colors.cyan('\n请选择操作:'));
1043
+ console.log(` ${colors.yellow('1')}. 检查 - 诊断配置和服务状态`);
1044
+ console.log(` ${colors.yellow('2')}. 更新 - 更新到最新版本`);
1045
+ console.log(` ${colors.yellow('3')}. 安装 - 重新安装(保留配置)`);
1046
+ console.log(` ${colors.yellow('4')}. 卸载 - 完全卸载 OpenClaw`);
1047
+ console.log(` ${colors.yellow('5')}. 配置模型 - 配置 AI 模型`);
1048
+ console.log(` ${colors.yellow('0')}. 退出`);
1049
+
1050
+ const choice = await askQuestion('\n请输入选项 (0-5): ');
1051
+
1052
+ switch (choice.trim()) {
1053
+ case '1':
1054
+ await runHealthCheck(cliName);
1055
+ await waitForEnter('\n按回车返回菜单...');
1056
+ break;
1057
+ case '2':
1058
+ await updateOpenClaw(cliName);
1059
+ await waitForEnter('\n按回车返回菜单...');
1060
+ break;
1061
+ case '3':
1062
+ console.log(colors.yellow('\n即将重新安装 OpenClaw...'));
1063
+ const confirmReinstall = await askQuestion('确认重新安装?(y/N): ');
1064
+ if (confirmReinstall.toLowerCase() === 'y') {
1065
+ await uninstallOpenClaw(existing);
1066
+ const newCliName = await installOpenClaw();
1067
+ await runOnboard(newCliName);
1068
+ showCompletionInfo(newCliName);
1069
+ }
1070
+ break;
1071
+ case '4':
1072
+ console.log(colors.red('\n⚠ 警告:卸载将删除所有配置!'));
1073
+ const confirmUninstall = await askQuestion('确认卸载?(y/N): ');
1074
+ if (confirmUninstall.toLowerCase() === 'y') {
1075
+ await uninstallOpenClaw(existing);
1076
+ console.log(colors.green('\n卸载完成,感谢使用 OpenClaw!'));
1077
+ process.exit(0);
1078
+ }
1079
+ break;
1080
+ case '5':
1081
+ console.log(colors.cyan('\n启动模型配置...'));
1082
+ spawnSync('npx', ['openclawapi@latest'], {
1083
+ stdio: 'inherit',
1084
+ shell: true,
1085
+ });
1086
+ await waitForEnter('\n按回车返回菜单...');
1087
+ break;
1088
+ case '0':
1089
+ case '':
1090
+ console.log(colors.gray('\n再见!'));
1091
+ process.exit(0);
1092
+ default:
1093
+ log.warn('无效选项,请输入 0-5');
1094
+ }
1095
+ }
1096
+ }
1097
+
1098
+ function askQuestion(prompt) {
1099
+ return new Promise((resolve) => {
1100
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
1101
+ rl.question(colors.yellow(prompt), (answer) => {
1102
+ rl.close();
1103
+ resolve(answer);
1104
+ });
1105
+ });
1106
+ }
1107
+
869
1108
  // ============ 主函数 ============
870
1109
 
871
1110
  async function main() {
@@ -888,6 +1127,11 @@ async function main() {
888
1127
  if (existing.installed) {
889
1128
  console.log(colors.green(`\n✓ 检测到已安装: ${existing.name}`));
890
1129
 
1130
+ if (options.check) {
1131
+ await runHealthCheck(existing.name);
1132
+ process.exit(0);
1133
+ }
1134
+
891
1135
  if (options.update) {
892
1136
  await updateOpenClaw(existing.name);
893
1137
  process.exit(0);
@@ -901,14 +1145,8 @@ async function main() {
901
1145
  if (options.reinstall) {
902
1146
  await uninstallOpenClaw(existing);
903
1147
  } else {
904
- console.log(colors.cyan('\n已安装,可选操作:'));
905
- console.log(` 更新: ${colors.yellow('npx openclawsetup --update')}`);
906
- console.log(` 重装: ${colors.yellow('npx openclawsetup --reinstall')}`);
907
- console.log(` 卸载: ${colors.yellow('npx openclawsetup --uninstall')}`);
908
- console.log(` 配置模型: ${colors.yellow('npx openclawapi@latest preset-claude')}`);
909
- showDashboardAccessInfo();
910
- console.log('');
911
- process.exit(0);
1148
+ // 交互式菜单
1149
+ await showInteractiveMenu(existing);
912
1150
  }
913
1151
  }
914
1152
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclawsetup",
3
- "version": "2.1.5",
3
+ "version": "2.2.0",
4
4
  "description": "OpenClaw 安装向导 - 带中文指引的官方安装流程",
5
5
  "type": "module",
6
6
  "bin": {