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.
Files changed (2) hide show
  1. package/bin/cli.mjs +71 -88
  2. 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
- 1. 使用手动模式:
553
- npx openclawsetup@latest --manual
554
- 2. 在 Linux 服务器上补齐编译依赖后再试:
555
- sudo apt-get install -y build-essential python3 make g++
556
- npx openclawsetup@latest --auto
557
- 3. 或直接运行官方命令:
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 (!usedAuto) {
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(port, token, model) {
1223
+ function testModelChat(cliName) {
1241
1224
  return new Promise((resolve) => {
1242
- const postData = JSON.stringify({ model, input: '请用一句话回复你的模型名称' });
1243
- const req = http.request({
1244
- hostname: '127.0.0.1',
1245
- port,
1246
- path: '/v1/responses',
1247
- method: 'POST',
1248
- timeout: 30000,
1249
- headers: {
1250
- 'Content-Type': 'application/json',
1251
- 'Authorization': `Bearer ${token}`,
1252
- 'Content-Length': Buffer.byteLength(postData),
1253
- },
1254
- }, (res) => {
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
- req.on('timeout', () => { req.destroy(); resolve({ success: false, error: '请求超时 (30s)' }); });
1274
- req.on('error', (e) => {
1275
- resolve({ success: false, error: e.code === 'ECONNREFUSED' ? 'Gateway 未响应' : e.message });
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 (config.token && config.token !== '<未配置>' && primaryModel) {
1325
+ if (primaryModel) {
1343
1326
  console.log(colors.gray(' … 正在测试模型对话...'));
1344
- const testResult = await testModelChat(port, config.token, primaryModel);
1327
+ const testResult = await testModelChat(cliName);
1345
1328
  if (testResult.success) {
1346
1329
  console.log(colors.green(' ✓ 模型对话正常'));
1347
1330
  if (testResult.message) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclawsetup",
3
- "version": "2.4.8",
3
+ "version": "2.5.0",
4
4
  "description": "OpenClaw 安装向导 - 智能安装、诊断、自动修复",
5
5
  "type": "module",
6
6
  "bin": {