openclawsetup 2.4.5 → 2.4.7
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 +68 -10
- package/install.sh +20 -0
- package/package.json +1 -1
package/bin/cli.mjs
CHANGED
|
@@ -148,20 +148,62 @@ function checkNodeVersion() {
|
|
|
148
148
|
|
|
149
149
|
function needsSudo() {
|
|
150
150
|
const os = platform();
|
|
151
|
-
if (os === 'win32'
|
|
151
|
+
if (os === 'win32') return false;
|
|
152
152
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
153
|
+
// 获取 npm 全局安装目录并检查写权限
|
|
154
|
+
const npmPrefixResult = safeExec('npm prefix -g');
|
|
155
|
+
if (npmPrefixResult.ok && npmPrefixResult.output) {
|
|
156
|
+
const globalDir = join(npmPrefixResult.output.trim(), 'lib', 'node_modules');
|
|
157
|
+
try {
|
|
158
|
+
if (existsSync(globalDir)) {
|
|
159
|
+
accessSync(globalDir, fsConstants.W_OK);
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
// 目录不存在,检查父目录
|
|
163
|
+
const parentDir = npmPrefixResult.output.trim();
|
|
164
|
+
if (existsSync(parentDir)) {
|
|
165
|
+
accessSync(parentDir, fsConstants.W_OK);
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
} catch {
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// 回退检查
|
|
174
|
+
const testDirs = os === 'darwin'
|
|
175
|
+
? ['/usr/local/lib/node_modules', '/opt/homebrew/lib/node_modules']
|
|
176
|
+
: ['/usr/lib/node_modules'];
|
|
177
|
+
for (const testDir of testDirs) {
|
|
178
|
+
try {
|
|
179
|
+
if (existsSync(testDir)) {
|
|
180
|
+
accessSync(testDir, fsConstants.W_OK);
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
} catch {
|
|
184
|
+
return true;
|
|
158
185
|
}
|
|
159
|
-
} catch {
|
|
160
|
-
return true;
|
|
161
186
|
}
|
|
162
187
|
return true;
|
|
163
188
|
}
|
|
164
189
|
|
|
190
|
+
function fixNpmCacheOwnership() {
|
|
191
|
+
// sudo npm install 会把 ~/.npm 的文件 owner 改成 root
|
|
192
|
+
// 导致后续普通用户的 npx 无法写缓存(EACCES)
|
|
193
|
+
if (platform() === 'win32') return;
|
|
194
|
+
const npmCacheDir = join(homedir(), '.npm');
|
|
195
|
+
if (!existsSync(npmCacheDir)) return;
|
|
196
|
+
try {
|
|
197
|
+
accessSync(npmCacheDir, fsConstants.W_OK);
|
|
198
|
+
} catch {
|
|
199
|
+
const user = process.env.USER || process.env.LOGNAME;
|
|
200
|
+
if (user) {
|
|
201
|
+
log.hint('修复 npm 缓存目录权限...');
|
|
202
|
+
safeExec(`sudo chown -R ${user} "${npmCacheDir}"`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
165
207
|
function detectExistingInstall() {
|
|
166
208
|
const home = homedir();
|
|
167
209
|
const openclawDir = join(home, '.openclaw');
|
|
@@ -397,7 +439,8 @@ async function installOpenClaw() {
|
|
|
397
439
|
console.log(colors.bold(colors.cyan('\n[1/2] 安装 OpenClaw CLI\n')));
|
|
398
440
|
|
|
399
441
|
if (useSudo) {
|
|
400
|
-
|
|
442
|
+
const osName = platform() === 'darwin' ? 'macOS' : 'Linux';
|
|
443
|
+
log.hint(`${osName} 系统需要 sudo 权限安装全局包`);
|
|
401
444
|
console.log(colors.yellow('\n请运行以下命令:'));
|
|
402
445
|
console.log(colors.green(' sudo npm install -g openclaw@latest\n'));
|
|
403
446
|
|
|
@@ -410,10 +453,11 @@ async function installOpenClaw() {
|
|
|
410
453
|
process.exit(1);
|
|
411
454
|
}
|
|
412
455
|
log.success(`OpenClaw 已安装: ${check.output}`);
|
|
456
|
+
fixNpmCacheOwnership();
|
|
413
457
|
return 'openclaw';
|
|
414
458
|
}
|
|
415
459
|
|
|
416
|
-
//
|
|
460
|
+
// 有权限:直接安装
|
|
417
461
|
console.log(colors.gray('正在安装 openclaw...\n'));
|
|
418
462
|
|
|
419
463
|
const result = spawnSync('npm', ['install', '-g', 'openclaw@latest'], {
|
|
@@ -426,6 +470,20 @@ async function installOpenClaw() {
|
|
|
426
470
|
return 'openclaw';
|
|
427
471
|
}
|
|
428
472
|
|
|
473
|
+
// 安装失败,可能是权限问题,尝试 sudo(非 Windows)
|
|
474
|
+
if (platform() !== 'win32') {
|
|
475
|
+
log.warn('安装失败,可能是权限不足,尝试使用 sudo...');
|
|
476
|
+
const sudoResult = spawnSync('sudo', ['npm', 'install', '-g', 'openclaw@latest'], {
|
|
477
|
+
stdio: 'inherit',
|
|
478
|
+
shell: true,
|
|
479
|
+
});
|
|
480
|
+
if (sudoResult.status === 0) {
|
|
481
|
+
fixNpmCacheOwnership();
|
|
482
|
+
log.success('OpenClaw CLI 安装完成(sudo)');
|
|
483
|
+
return 'openclaw';
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
429
487
|
// 尝试 clawdbot
|
|
430
488
|
log.warn('openclaw 安装失败,尝试 clawdbot...');
|
|
431
489
|
const fallback = spawnSync('npm', ['install', '-g', 'clawdbot@latest'], {
|
package/install.sh
CHANGED
|
@@ -258,6 +258,7 @@ install_node() {
|
|
|
258
258
|
# 验证安装
|
|
259
259
|
if command -v node &> /dev/null; then
|
|
260
260
|
log_success "Node.js 安装完成: $(node -v)"
|
|
261
|
+
fix_npm_cache_ownership
|
|
261
262
|
else
|
|
262
263
|
log_error "Node.js 安装失败"
|
|
263
264
|
echo ""
|
|
@@ -401,6 +402,22 @@ show_installed_info() {
|
|
|
401
402
|
echo " 飞书: npx openclaw-chat-cn@latest feishu"
|
|
402
403
|
}
|
|
403
404
|
|
|
405
|
+
# 修复 npm 缓存目录权限(sudo 安装后 ~/.npm 可能被 root 占用)
|
|
406
|
+
fix_npm_cache_ownership() {
|
|
407
|
+
local npm_cache="$HOME/.npm"
|
|
408
|
+
if [ -d "$npm_cache" ]; then
|
|
409
|
+
local current_user
|
|
410
|
+
current_user=$(whoami 2>/dev/null || echo "")
|
|
411
|
+
if [ -n "$current_user" ] && [ "$current_user" != "root" ]; then
|
|
412
|
+
# 检查是否有 root 拥有的文件
|
|
413
|
+
if find "$npm_cache" -maxdepth 1 -user root 2>/dev/null | grep -q .; then
|
|
414
|
+
log_info "修复 npm 缓存目录权限..."
|
|
415
|
+
sudo chown -R "$current_user" "$npm_cache" 2>/dev/null || true
|
|
416
|
+
fi
|
|
417
|
+
fi
|
|
418
|
+
fi
|
|
419
|
+
}
|
|
420
|
+
|
|
404
421
|
# 显示菜单并获取选择
|
|
405
422
|
show_menu() {
|
|
406
423
|
local choice=""
|
|
@@ -541,6 +558,9 @@ install_openclaw() {
|
|
|
541
558
|
log_info "开始安装 OpenClaw..."
|
|
542
559
|
echo ""
|
|
543
560
|
|
|
561
|
+
# 修复 npm 缓存权限(防止之前 sudo 导致的 EACCES)
|
|
562
|
+
fix_npm_cache_ownership
|
|
563
|
+
|
|
544
564
|
# 清除 npm 缓存确保获取最新版本
|
|
545
565
|
log_info "清除 npm 缓存..."
|
|
546
566
|
npm cache clean --force 2>/dev/null || true
|