openclawsetup 2.4.8 → 2.5.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 +71 -88
- package/package.json +1 -1
package/bin/cli.mjs
CHANGED
|
@@ -10,9 +10,8 @@
|
|
|
10
10
|
* npx openclawsetup --update # 更新已安装的 OpenClaw
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { execSync, spawnSync } from 'child_process';
|
|
13
|
+
import { exec, execSync, spawnSync } from 'child_process';
|
|
14
14
|
import { existsSync, accessSync, constants as fsConstants, rmSync, readFileSync } from 'fs';
|
|
15
|
-
import http from 'http';
|
|
16
15
|
import { homedir, platform } from 'os';
|
|
17
16
|
import { join } from 'path';
|
|
18
17
|
import { createInterface } from 'readline';
|
|
@@ -513,64 +512,48 @@ async function installOpenClaw() {
|
|
|
513
512
|
async function runOnboard(cliName) {
|
|
514
513
|
console.log(colors.bold(colors.cyan('\n[2/2] 运行配置向导\n')));
|
|
515
514
|
|
|
516
|
-
// 显示指引
|
|
517
|
-
showInstallGuide();
|
|
518
|
-
|
|
519
|
-
await waitForEnter('准备好了吗?按回车开始配置...');
|
|
520
|
-
|
|
521
|
-
console.log(colors.gray('\n' + '-'.repeat(60)));
|
|
522
|
-
console.log(colors.gray('以下是官方 openclaw onboard 界面:'));
|
|
523
|
-
console.log(colors.gray('-'.repeat(60) + '\n'));
|
|
524
|
-
|
|
525
515
|
const options = parseArgs();
|
|
526
|
-
const preferAuto = !options.manual;
|
|
527
|
-
let usedAuto = false;
|
|
528
|
-
|
|
529
|
-
if (preferAuto) {
|
|
530
|
-
const flagResult = runOnboardFlags(cliName, options);
|
|
531
|
-
if (flagResult.ran) {
|
|
532
|
-
usedAuto = true;
|
|
533
|
-
console.log(colors.gray('\n' + '-'.repeat(60)));
|
|
534
|
-
if (!flagResult.ok) {
|
|
535
|
-
log.warn(`onboard 退出码: ${flagResult.exitCode}`);
|
|
536
|
-
log.hint('如果配置未完成,可以手动运行: ' + cliName + ' onboard');
|
|
537
|
-
}
|
|
538
|
-
} else {
|
|
539
|
-
const autoResult = await runOnboardAuto(cliName, options);
|
|
540
|
-
if (autoResult.ok) {
|
|
541
|
-
usedAuto = true;
|
|
542
|
-
console.log(colors.gray('\n' + '-'.repeat(60)));
|
|
543
|
-
if (autoResult.exitCode !== 0) {
|
|
544
|
-
log.warn(`onboard 退出码: ${autoResult.exitCode}`);
|
|
545
|
-
log.hint('如果配置未完成,可以手动运行: ' + cliName + ' onboard');
|
|
546
|
-
}
|
|
547
|
-
} else if (options.auto) {
|
|
548
|
-
exitWithError('PTY_UNAVAILABLE', `
|
|
549
|
-
原因: ${autoResult.reason || '未能启用自动应答'}
|
|
550
516
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
npm install -g openclaw@latest
|
|
559
|
-
openclaw onboard --install-daemon`);
|
|
560
|
-
} else {
|
|
561
|
-
log.warn('自动模式不可用,已切换为手动模式');
|
|
562
|
-
log.hint(autoResult.reason || '未能启用自动应答');
|
|
563
|
-
}
|
|
564
|
-
}
|
|
517
|
+
// 让用户选择安装模式
|
|
518
|
+
let mode = options.manual ? '2' : options.auto ? '1' : '';
|
|
519
|
+
if (!mode) {
|
|
520
|
+
console.log(colors.cyan('请选择安装模式:'));
|
|
521
|
+
console.log(` ${colors.yellow('1')}. 自动安装(跳过所有配置,后续单独配置模型和渠道)`);
|
|
522
|
+
console.log(` ${colors.yellow('2')}. 手动安装(走官方 onboard 完整流程)`);
|
|
523
|
+
mode = await askQuestion('\n请选择 (1/2): ');
|
|
565
524
|
}
|
|
566
525
|
|
|
567
|
-
if (
|
|
526
|
+
if (mode.trim() === '2') {
|
|
527
|
+
// 手动模式:直接运行官方 onboard
|
|
528
|
+
console.log(colors.gray('\n' + '-'.repeat(60)));
|
|
529
|
+
console.log(colors.gray('以下是官方 openclaw onboard 界面:'));
|
|
530
|
+
console.log(colors.gray('-'.repeat(60) + '\n'));
|
|
531
|
+
|
|
568
532
|
const manualResult = runOnboardManual(cliName);
|
|
569
533
|
console.log(colors.gray('\n' + '-'.repeat(60)));
|
|
570
534
|
if (manualResult.status !== 0) {
|
|
571
535
|
log.warn(`onboard 退出码: ${manualResult.status}`);
|
|
572
536
|
log.hint('如果配置未完成,可以手动运行: ' + cliName + ' onboard');
|
|
573
537
|
}
|
|
538
|
+
} else {
|
|
539
|
+
// 自动模式:只用最安全的参数
|
|
540
|
+
console.log(colors.gray('\n正在自动安装(跳过模型和渠道配置)...\n'));
|
|
541
|
+
|
|
542
|
+
const { file, args } = getOnboardCommand(cliName, ['onboard', '--install-daemon']);
|
|
543
|
+
const result = spawnSync(file, args, { stdio: 'inherit' });
|
|
544
|
+
|
|
545
|
+
if (result.status !== 0) {
|
|
546
|
+
// 自动模式失败,回退到手动
|
|
547
|
+
log.warn('自动安装未完成,切换到手动模式...');
|
|
548
|
+
console.log(colors.gray('\n' + '-'.repeat(60)));
|
|
549
|
+
console.log(colors.gray('以下是官方 openclaw onboard 界面:'));
|
|
550
|
+
console.log(colors.gray('-'.repeat(60) + '\n'));
|
|
551
|
+
const manualResult = runOnboardManual(cliName);
|
|
552
|
+
if (manualResult.status !== 0) {
|
|
553
|
+
log.warn(`onboard 退出码: ${manualResult.status}`);
|
|
554
|
+
log.hint('如果配置未完成,可以手动运行: ' + cliName + ' onboard');
|
|
555
|
+
}
|
|
556
|
+
}
|
|
574
557
|
}
|
|
575
558
|
}
|
|
576
559
|
|
|
@@ -1237,45 +1220,45 @@ async function runHealthCheck(cliName, autoFix = false) {
|
|
|
1237
1220
|
|
|
1238
1221
|
// ============ 交互式菜单 ============
|
|
1239
1222
|
|
|
1240
|
-
function testModelChat(
|
|
1223
|
+
function testModelChat(cliName) {
|
|
1241
1224
|
return new Promise((resolve) => {
|
|
1242
|
-
const
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
'
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
let data = '';
|
|
1256
|
-
res.on('data', chunk => data += chunk);
|
|
1257
|
-
res.on('end', () => {
|
|
1258
|
-
try {
|
|
1259
|
-
const json = JSON.parse(data);
|
|
1260
|
-
const text = json.output?.[0]?.content?.[0]?.text;
|
|
1261
|
-
if (text) {
|
|
1262
|
-
resolve({ success: true, message: text });
|
|
1263
|
-
} else if (json.error) {
|
|
1264
|
-
resolve({ success: false, error: json.error.message || JSON.stringify(json.error) });
|
|
1265
|
-
} else {
|
|
1266
|
-
resolve({ success: false, error: `HTTP ${res.statusCode}: ${data.substring(0, 200)}` });
|
|
1267
|
-
}
|
|
1268
|
-
} catch {
|
|
1269
|
-
resolve({ success: false, error: `HTTP ${res.statusCode}: ${data.substring(0, 200)}` });
|
|
1225
|
+
const cmd = `${cliName} agent --session-id openclawsetup-test --message "请用一句话回复你的模型名称" --json --timeout 60`;
|
|
1226
|
+
exec(cmd, { timeout: 65000 }, (error, stdout, stderr) => {
|
|
1227
|
+
if (error) {
|
|
1228
|
+
const errMsg = (stderr || stdout || error.message || '').trim();
|
|
1229
|
+
// 提取关键错误信息
|
|
1230
|
+
if (errMsg.includes('401')) {
|
|
1231
|
+
resolve({ success: false, error: 'API Key 无效 (401)' });
|
|
1232
|
+
} else if (errMsg.includes('403')) {
|
|
1233
|
+
resolve({ success: false, error: 'API 访问被拒绝 (403)' });
|
|
1234
|
+
} else if (errMsg.includes('timeout') || errMsg.includes('ETIMEDOUT')) {
|
|
1235
|
+
resolve({ success: false, error: '请求超时,节点可能不可达' });
|
|
1236
|
+
} else {
|
|
1237
|
+
resolve({ success: false, error: errMsg.substring(0, 200) || 'CLI 执行失败' });
|
|
1270
1238
|
}
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1239
|
+
return;
|
|
1240
|
+
}
|
|
1241
|
+
const output = (stdout || '').trim();
|
|
1242
|
+
const jsonStart = output.indexOf('{');
|
|
1243
|
+
const jsonEnd = output.lastIndexOf('}');
|
|
1244
|
+
if (jsonStart === -1 || jsonEnd === -1 || jsonEnd <= jsonStart) {
|
|
1245
|
+
resolve({ success: false, error: '返回格式异常' });
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
try {
|
|
1249
|
+
const parsed = JSON.parse(output.slice(jsonStart, jsonEnd + 1));
|
|
1250
|
+
const message = parsed?.result?.payloads?.[0]?.text || '';
|
|
1251
|
+
const provider = parsed?.result?.meta?.agentMeta?.provider || '';
|
|
1252
|
+
const modelId = parsed?.result?.meta?.agentMeta?.model || '';
|
|
1253
|
+
if (message || (provider && modelId)) {
|
|
1254
|
+
resolve({ success: true, message, provider, model: modelId });
|
|
1255
|
+
} else {
|
|
1256
|
+
resolve({ success: false, error: '模型未返回内容' });
|
|
1257
|
+
}
|
|
1258
|
+
} catch {
|
|
1259
|
+
resolve({ success: false, error: '返回 JSON 解析失败' });
|
|
1260
|
+
}
|
|
1276
1261
|
});
|
|
1277
|
-
req.write(postData);
|
|
1278
|
-
req.end();
|
|
1279
1262
|
});
|
|
1280
1263
|
}
|
|
1281
1264
|
|
|
@@ -1339,9 +1322,9 @@ async function showStatusInfo(cliName) {
|
|
|
1339
1322
|
}
|
|
1340
1323
|
|
|
1341
1324
|
// 模型对话测试
|
|
1342
|
-
if (
|
|
1325
|
+
if (primaryModel) {
|
|
1343
1326
|
console.log(colors.gray(' … 正在测试模型对话...'));
|
|
1344
|
-
const testResult = await testModelChat(
|
|
1327
|
+
const testResult = await testModelChat(cliName);
|
|
1345
1328
|
if (testResult.success) {
|
|
1346
1329
|
console.log(colors.green(' ✓ 模型对话正常'));
|
|
1347
1330
|
if (testResult.message) {
|