openclawsetup 2.1.4 → 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.
- package/bin/cli.mjs +305 -25
- package/install.ps1 +1 -1
- package/install.sh +35 -8
- package/package.json +6 -1
- package//344/275/277/347/224/250/350/257/264/346/230/216.md +94 -0
package/bin/cli.mjs
CHANGED
|
@@ -16,6 +16,32 @@ import { homedir, platform } from 'os';
|
|
|
16
16
|
import { join } from 'path';
|
|
17
17
|
import { createInterface } from 'readline';
|
|
18
18
|
|
|
19
|
+
// ============ 错误码定义 ============
|
|
20
|
+
|
|
21
|
+
const ERROR_CODES = {
|
|
22
|
+
NODE_VERSION: { code: 1, message: 'Node.js 版本过低' },
|
|
23
|
+
OPENCLAW_NOT_FOUND: { code: 2, message: '未检测到 OpenClaw 安装' },
|
|
24
|
+
NPM_INSTALL_FAILED: { code: 3, message: 'npm 安装失败' },
|
|
25
|
+
ONBOARD_FAILED: { code: 4, message: 'onboard 执行失败' },
|
|
26
|
+
GATEWAY_RESTART_FAILED: { code: 5, message: 'Gateway 重启失败' },
|
|
27
|
+
INVALID_INPUT: { code: 6, message: '输入无效' },
|
|
28
|
+
PERMISSION_DENIED: { code: 7, message: '权限不足' },
|
|
29
|
+
NETWORK_ERROR: { code: 8, message: '网络错误' },
|
|
30
|
+
PTY_UNAVAILABLE: { code: 9, message: '自动模式不可用' },
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
function exitWithError(errorType, details = '') {
|
|
34
|
+
const err = ERROR_CODES[errorType] || { code: 99, message: '未知错误' };
|
|
35
|
+
console.log('\n' + '='.repeat(40));
|
|
36
|
+
console.log(`\x1b[31m❌ 错误: ${err.message}\x1b[0m`);
|
|
37
|
+
console.log('='.repeat(40));
|
|
38
|
+
if (details) {
|
|
39
|
+
console.log(details);
|
|
40
|
+
}
|
|
41
|
+
console.log(`\n错误码: ${err.code}`);
|
|
42
|
+
process.exit(err.code);
|
|
43
|
+
}
|
|
44
|
+
|
|
19
45
|
// ============ 工具函数 ============
|
|
20
46
|
|
|
21
47
|
const colors = {
|
|
@@ -52,6 +78,7 @@ function parseArgs() {
|
|
|
52
78
|
update: args.includes('--update'),
|
|
53
79
|
reinstall: args.includes('--reinstall'),
|
|
54
80
|
uninstall: args.includes('--uninstall'),
|
|
81
|
+
check: args.includes('--check'),
|
|
55
82
|
manual: args.includes('--manual'),
|
|
56
83
|
auto: args.includes('--auto'),
|
|
57
84
|
withModel: args.includes('--with-model'),
|
|
@@ -65,7 +92,8 @@ function showHelp() {
|
|
|
65
92
|
${colors.bold('OpenClaw 安装向导')}
|
|
66
93
|
|
|
67
94
|
${colors.cyan('用法:')}
|
|
68
|
-
npx openclawsetup
|
|
95
|
+
npx openclawsetup 交互式菜单(已安装)/ 安装向导(未安装)
|
|
96
|
+
npx openclawsetup --check 检查配置和服务状态
|
|
69
97
|
npx openclawsetup --update 更新已安装的 OpenClaw
|
|
70
98
|
npx openclawsetup --reinstall 卸载后重新安装
|
|
71
99
|
npx openclawsetup --uninstall 卸载 OpenClaw
|
|
@@ -91,11 +119,14 @@ function checkNodeVersion() {
|
|
|
91
119
|
const version = process.version;
|
|
92
120
|
const major = parseInt(version.slice(1).split('.')[0], 10);
|
|
93
121
|
if (major < 18) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
122
|
+
exitWithError('NODE_VERSION', `
|
|
123
|
+
当前版本: ${version},需要 18+
|
|
124
|
+
|
|
125
|
+
解决方案:
|
|
126
|
+
1. 访问 https://nodejs.org/ 下载最新版本
|
|
127
|
+
2. 或使用 nvm: nvm install 22
|
|
128
|
+
3. 或使用一键脚本(自动安装 Node.js):
|
|
129
|
+
curl -fsSL https://unpkg.com/openclawsetup@latest/install.sh | bash`);
|
|
99
130
|
}
|
|
100
131
|
return true;
|
|
101
132
|
}
|
|
@@ -161,9 +192,9 @@ function getConfigInfo() {
|
|
|
161
192
|
} catch {
|
|
162
193
|
try {
|
|
163
194
|
const raw = readFileSync(configPath, 'utf8');
|
|
164
|
-
const tokenMatch = raw.match(/"token"
|
|
165
|
-
const portMatch = raw.match(/"port"
|
|
166
|
-
const bindMatch = raw.match(/"bind"
|
|
195
|
+
const tokenMatch = raw.match(/"token"\s*:\s*"([^"]+)"/i);
|
|
196
|
+
const portMatch = raw.match(/"port"\s*:\s*(\d+)/i);
|
|
197
|
+
const bindMatch = raw.match(/"bind"\s*:\s*"([^"]+)"/i);
|
|
167
198
|
return {
|
|
168
199
|
configDir: cfg.dir,
|
|
169
200
|
configPath,
|
|
@@ -382,11 +413,15 @@ async function installOpenClaw() {
|
|
|
382
413
|
return 'clawdbot';
|
|
383
414
|
}
|
|
384
415
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
416
|
+
exitWithError('NPM_INSTALL_FAILED', `
|
|
417
|
+
解决方案:
|
|
418
|
+
1. 检查网络连接
|
|
419
|
+
2. 清除 npm 缓存后重试:
|
|
420
|
+
npm cache clean --force
|
|
421
|
+
npx openclawsetup@latest
|
|
422
|
+
3. 手动安装:
|
|
423
|
+
npm install -g openclaw@latest
|
|
424
|
+
openclaw onboard --install-daemon`);
|
|
390
425
|
}
|
|
391
426
|
|
|
392
427
|
// ============ 运行 Onboard ============
|
|
@@ -426,9 +461,18 @@ async function runOnboard(cliName) {
|
|
|
426
461
|
log.hint('如果配置未完成,可以手动运行: ' + cliName + ' onboard');
|
|
427
462
|
}
|
|
428
463
|
} else if (options.auto) {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
464
|
+
exitWithError('PTY_UNAVAILABLE', `
|
|
465
|
+
原因: ${autoResult.reason || '未能启用自动应答'}
|
|
466
|
+
|
|
467
|
+
解决方案:
|
|
468
|
+
1. 使用手动模式:
|
|
469
|
+
npx openclawsetup@latest --manual
|
|
470
|
+
2. 在 Linux 服务器上补齐编译依赖后再试:
|
|
471
|
+
sudo apt-get install -y build-essential python3 make g++
|
|
472
|
+
npx openclawsetup@latest --auto
|
|
473
|
+
3. 或直接运行官方命令:
|
|
474
|
+
npm install -g openclaw@latest
|
|
475
|
+
openclaw onboard --install-daemon`);
|
|
432
476
|
} else {
|
|
433
477
|
log.warn('自动模式不可用,已切换为手动模式');
|
|
434
478
|
log.hint(autoResult.reason || '未能启用自动应答');
|
|
@@ -824,6 +868,243 @@ async function uninstallOpenClaw(existing) {
|
|
|
824
868
|
log.success('卸载完成');
|
|
825
869
|
}
|
|
826
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
|
+
|
|
827
1108
|
// ============ 主函数 ============
|
|
828
1109
|
|
|
829
1110
|
async function main() {
|
|
@@ -846,6 +1127,11 @@ async function main() {
|
|
|
846
1127
|
if (existing.installed) {
|
|
847
1128
|
console.log(colors.green(`\n✓ 检测到已安装: ${existing.name}`));
|
|
848
1129
|
|
|
1130
|
+
if (options.check) {
|
|
1131
|
+
await runHealthCheck(existing.name);
|
|
1132
|
+
process.exit(0);
|
|
1133
|
+
}
|
|
1134
|
+
|
|
849
1135
|
if (options.update) {
|
|
850
1136
|
await updateOpenClaw(existing.name);
|
|
851
1137
|
process.exit(0);
|
|
@@ -859,14 +1145,8 @@ async function main() {
|
|
|
859
1145
|
if (options.reinstall) {
|
|
860
1146
|
await uninstallOpenClaw(existing);
|
|
861
1147
|
} else {
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
console.log(` 重装: ${colors.yellow('npx openclawsetup --reinstall')}`);
|
|
865
|
-
console.log(` 卸载: ${colors.yellow('npx openclawsetup --uninstall')}`);
|
|
866
|
-
console.log(` 配置模型: ${colors.yellow('npx openclawapi@latest preset-claude')}`);
|
|
867
|
-
showDashboardAccessInfo();
|
|
868
|
-
console.log('');
|
|
869
|
-
process.exit(0);
|
|
1148
|
+
// 交互式菜单
|
|
1149
|
+
await showInteractiveMenu(existing);
|
|
870
1150
|
}
|
|
871
1151
|
}
|
|
872
1152
|
|
package/install.ps1
CHANGED
package/install.sh
CHANGED
|
@@ -190,25 +190,52 @@ install_node() {
|
|
|
190
190
|
nvm alias default 22
|
|
191
191
|
fi
|
|
192
192
|
elif [ "$OS" == "linux" ]; then
|
|
193
|
+
# 检查是否需要 sudo
|
|
194
|
+
local need_sudo=false
|
|
195
|
+
if [ "$(id -u)" -ne 0 ]; then
|
|
196
|
+
case "$PM" in
|
|
197
|
+
apt|dnf|yum|pacman|apk)
|
|
198
|
+
need_sudo=true
|
|
199
|
+
;;
|
|
200
|
+
esac
|
|
201
|
+
fi
|
|
202
|
+
|
|
203
|
+
if [ "$need_sudo" = true ] && ! command -v sudo &> /dev/null; then
|
|
204
|
+
log_error "需要 root 权限安装 Node.js"
|
|
205
|
+
echo ""
|
|
206
|
+
echo "请使用以下方式之一:"
|
|
207
|
+
echo " 1. 以 root 用户运行此脚本"
|
|
208
|
+
echo " 2. 安装 sudo 后重试"
|
|
209
|
+
echo " 3. 手动安装 Node.js: https://nodejs.org/"
|
|
210
|
+
echo ""
|
|
211
|
+
exit 7
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
local SUDO_CMD=""
|
|
215
|
+
if [ "$need_sudo" = true ]; then
|
|
216
|
+
SUDO_CMD="sudo"
|
|
217
|
+
log_warn "需要 sudo 权限安装 Node.js,可能会提示输入密码"
|
|
218
|
+
fi
|
|
219
|
+
|
|
193
220
|
case "$PM" in
|
|
194
221
|
apt)
|
|
195
222
|
log_info "使用 NodeSource 安装..."
|
|
196
|
-
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
|
|
197
|
-
apt-get install -y nodejs
|
|
223
|
+
curl -fsSL https://deb.nodesource.com/setup_22.x | $SUDO_CMD bash -
|
|
224
|
+
$SUDO_CMD apt-get install -y nodejs
|
|
198
225
|
;;
|
|
199
226
|
dnf)
|
|
200
|
-
curl -fsSL https://rpm.nodesource.com/setup_22.x | bash -
|
|
201
|
-
dnf install -y nodejs
|
|
227
|
+
curl -fsSL https://rpm.nodesource.com/setup_22.x | $SUDO_CMD bash -
|
|
228
|
+
$SUDO_CMD dnf install -y nodejs
|
|
202
229
|
;;
|
|
203
230
|
yum)
|
|
204
|
-
curl -fsSL https://rpm.nodesource.com/setup_22.x | bash -
|
|
205
|
-
yum install -y nodejs
|
|
231
|
+
curl -fsSL https://rpm.nodesource.com/setup_22.x | $SUDO_CMD bash -
|
|
232
|
+
$SUDO_CMD yum install -y nodejs
|
|
206
233
|
;;
|
|
207
234
|
pacman)
|
|
208
|
-
pacman -Sy --noconfirm nodejs npm
|
|
235
|
+
$SUDO_CMD pacman -Sy --noconfirm nodejs npm
|
|
209
236
|
;;
|
|
210
237
|
apk)
|
|
211
|
-
apk add --no-cache nodejs npm
|
|
238
|
+
$SUDO_CMD apk add --no-cache nodejs npm
|
|
212
239
|
;;
|
|
213
240
|
*)
|
|
214
241
|
log_info "使用 nvm 安装..."
|
package/package.json
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openclawsetup",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "OpenClaw 安装向导 - 带中文指引的官方安装流程",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"openclawsetup": "bin/cli.mjs"
|
|
8
8
|
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/anthropics/openclaw-tools.git",
|
|
12
|
+
"directory": "packages/openclawsetup"
|
|
13
|
+
},
|
|
9
14
|
"optionalDependencies": {
|
|
10
15
|
"node-pty": "^1.0.0"
|
|
11
16
|
},
|
|
@@ -233,6 +233,100 @@ rm ~/.config/systemd/user/openclaw.service
|
|
|
233
233
|
systemctl --user daemon-reload
|
|
234
234
|
```
|
|
235
235
|
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
### 错误:权限不足
|
|
239
|
+
**现象**:提示 "permission denied" 或 "EACCES"
|
|
240
|
+
**原因**:npm 全局安装目录没有写入权限
|
|
241
|
+
**解决**:
|
|
242
|
+
1. Linux 用户使用 sudo:
|
|
243
|
+
```bash
|
|
244
|
+
sudo npm install -g openclaw@latest
|
|
245
|
+
```
|
|
246
|
+
2. 或修复 npm 权限(推荐):
|
|
247
|
+
```bash
|
|
248
|
+
mkdir -p ~/.npm-global
|
|
249
|
+
npm config set prefix '~/.npm-global'
|
|
250
|
+
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
|
|
251
|
+
source ~/.bashrc
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
错误码: 7
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
### 错误:网络连接失败
|
|
259
|
+
**现象**:提示 "ETIMEDOUT"、"ECONNREFUSED" 或下载超时
|
|
260
|
+
**原因**:网络问题或 npm 源不可达
|
|
261
|
+
**解决**:
|
|
262
|
+
1. 检查网络连接
|
|
263
|
+
2. 尝试使用国内镜像源:
|
|
264
|
+
```bash
|
|
265
|
+
npm config set registry https://registry.npmmirror.com
|
|
266
|
+
npx openclawsetup@latest
|
|
267
|
+
```
|
|
268
|
+
3. 恢复官方源:
|
|
269
|
+
```bash
|
|
270
|
+
npm config set registry https://registry.npmjs.org
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
错误码: 8
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
### 错误:node-pty 编译失败
|
|
278
|
+
**现象**:安装时提示 "gyp ERR!" 或 "node-pty" 相关错误
|
|
279
|
+
**原因**:缺少 C++ 编译工具链
|
|
280
|
+
**解决**:
|
|
281
|
+
|
|
282
|
+
**Ubuntu/Debian:**
|
|
283
|
+
```bash
|
|
284
|
+
sudo apt-get update
|
|
285
|
+
sudo apt-get install -y build-essential python3 make g++ pkg-config
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**CentOS/RHEL:**
|
|
289
|
+
```bash
|
|
290
|
+
sudo yum groupinstall -y "Development Tools"
|
|
291
|
+
sudo yum install -y python3
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
**macOS:**
|
|
295
|
+
```bash
|
|
296
|
+
xcode-select --install
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Windows:**
|
|
300
|
+
```powershell
|
|
301
|
+
npm install -g windows-build-tools
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
安装依赖后重试:
|
|
305
|
+
```bash
|
|
306
|
+
npx openclawsetup@latest
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
如果仍然失败,可以使用手动模式(不需要 node-pty):
|
|
310
|
+
```bash
|
|
311
|
+
npx openclawsetup@latest --manual
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## 错误码速查表
|
|
317
|
+
|
|
318
|
+
| 错误码 | 含义 | 常见原因 |
|
|
319
|
+
|--------|------|----------|
|
|
320
|
+
| 1 | Node.js 版本过低 | 需要 Node.js 18+ |
|
|
321
|
+
| 2 | 未检测到 OpenClaw | 安装未完成 |
|
|
322
|
+
| 3 | npm 安装失败 | 网络问题或权限问题 |
|
|
323
|
+
| 4 | onboard 执行失败 | 配置过程中断 |
|
|
324
|
+
| 5 | Gateway 重启失败 | 服务异常 |
|
|
325
|
+
| 6 | 输入无效 | 参数错误 |
|
|
326
|
+
| 7 | 权限不足 | 需要 sudo 或修复 npm 权限 |
|
|
327
|
+
| 8 | 网络错误 | 检查网络或更换镜像源 |
|
|
328
|
+
| 9 | 自动模式不可用 | 缺少编译依赖,使用 --manual |
|
|
329
|
+
|
|
236
330
|
## 获取帮助
|
|
237
331
|
|
|
238
332
|
```bash
|