openclawsetup 2.8.10 → 2.8.11

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 +123 -4
  2. package/package.json +1 -1
package/bin/cli.mjs CHANGED
@@ -1286,9 +1286,13 @@ async function tryFixPortConflict(cliName, currentPort) {
1286
1286
  return { ok: false, newPort: currentPort, note: '未找到可用替代端口' };
1287
1287
  }
1288
1288
 
1289
- const setResult = safeExec(`${cliName} config set gateway.port ${availablePort}`);
1289
+ // 优先用 CLI 设置,超时则直接改配置文件
1290
+ const setResult = safeExec(`${cliName} config set gateway.port ${availablePort}`, { timeout: 10000 });
1290
1291
  if (!setResult.ok) {
1291
- return { ok: false, newPort: currentPort, note: `端口切换失败: ${setResult.stderr || setResult.error}` };
1292
+ const fileSet = setGatewayPortInConfig(availablePort);
1293
+ if (!fileSet.ok) {
1294
+ return { ok: false, newPort: currentPort, note: `端口切换失败: ${fileSet.error}` };
1295
+ }
1292
1296
  }
1293
1297
 
1294
1298
  const restartResult = await ensureGatewayRunning(cliName, 'restart');
@@ -1299,6 +1303,109 @@ async function tryFixPortConflict(cliName, currentPort) {
1299
1303
  return { ok: true, newPort: availablePort, note: `端口已切换到 ${availablePort}` };
1300
1304
  }
1301
1305
 
1306
+ /**
1307
+ * 直接修改 openclaw.json 中的 gateway.port(不依赖 openclaw CLI)
1308
+ */
1309
+ function setGatewayPortInConfig(newPort) {
1310
+ const config = getConfigInfo();
1311
+ if (!config.configPath || !existsSync(config.configPath)) {
1312
+ return { ok: false, error: '配置文件不存在' };
1313
+ }
1314
+ try {
1315
+ const raw = readFileSync(config.configPath, 'utf8');
1316
+ const json = JSON.parse(raw);
1317
+ if (!json.gateway) json.gateway = {};
1318
+ json.gateway.port = newPort;
1319
+ writeFileSync(config.configPath, JSON.stringify(json, null, 2), 'utf8');
1320
+ return { ok: true };
1321
+ } catch (e) {
1322
+ return { ok: false, error: e.message };
1323
+ }
1324
+ }
1325
+
1326
+ /**
1327
+ * 重置/更改端口:找可用端口 → 写配置 → 重启 Gateway
1328
+ */
1329
+ async function resetGatewayPort(cliName, requestedPort = null) {
1330
+ const config = getConfigInfo();
1331
+ const currentPort = config.port || DEFAULT_GATEWAY_PORT;
1332
+
1333
+ console.log(colors.cyan('\n🔧 Gateway 端口管理\n'));
1334
+ console.log(colors.gray(` 当前端口: ${currentPort}`));
1335
+
1336
+ // 确定目标端口
1337
+ let targetPort;
1338
+ if (requestedPort && requestedPort !== currentPort) {
1339
+ // 用户指定了端口,检查是否可用
1340
+ const inUse = await isPortInUse(requestedPort);
1341
+ if (inUse) {
1342
+ const processInfo = detectGatewayProcess(requestedPort);
1343
+ if (processInfo.found) {
1344
+ log.error(`端口 ${requestedPort} 已被占用: ${processInfo.processName || '未知'} (PID ${processInfo.pid})`);
1345
+ } else {
1346
+ log.error(`端口 ${requestedPort} 已被占用`);
1347
+ }
1348
+ return { ok: false, port: currentPort };
1349
+ }
1350
+ targetPort = requestedPort;
1351
+ } else {
1352
+ // 自动找可用端口
1353
+ console.log(colors.gray(' 正在扫描可用端口...'));
1354
+ targetPort = await findAvailablePort(DEFAULT_GATEWAY_PORT);
1355
+ if (!targetPort) {
1356
+ log.error('未找到可用端口');
1357
+ return { ok: false, port: currentPort };
1358
+ }
1359
+ }
1360
+
1361
+ console.log(colors.cyan(` 目标端口: ${targetPort}`));
1362
+
1363
+ // 先尝试用 CLI 设置(如果可用)
1364
+ const cliSet = safeExec(`${cliName} config set gateway.port ${targetPort}`, { timeout: 10000 });
1365
+ if (!cliSet.ok) {
1366
+ // CLI 不可用,直接改配置文件
1367
+ console.log(colors.gray(' CLI 设置超时,直接修改配置文件...'));
1368
+ const fileSet = setGatewayPortInConfig(targetPort);
1369
+ if (!fileSet.ok) {
1370
+ log.error(`配置写入失败: ${fileSet.error}`);
1371
+ return { ok: false, port: currentPort };
1372
+ }
1373
+ }
1374
+
1375
+ log.success(`端口已设置为 ${targetPort}`);
1376
+
1377
+ // 重启 Gateway
1378
+ console.log(colors.gray(' 正在重启 Gateway...'));
1379
+ await ensureGatewayRunning(cliName, 'restart');
1380
+
1381
+ // 等待并验证新端口
1382
+ const maxWait = platform() === 'win32' ? 15000 : 8000;
1383
+ const interval = 1500;
1384
+ let waited = 0;
1385
+ let portReady = false;
1386
+ while (waited < maxWait) {
1387
+ await sleep(interval);
1388
+ waited += interval;
1389
+ const check = getPortCheckOutput(targetPort);
1390
+ if (check.ok && hasListeningState(check.output)) {
1391
+ portReady = true;
1392
+ break;
1393
+ }
1394
+ }
1395
+
1396
+ if (portReady) {
1397
+ log.success(`Gateway 已在端口 ${targetPort} 上运行`);
1398
+ const token = getDashboardToken(config);
1399
+ if (token) {
1400
+ console.log(colors.cyan(`\n Dashboard: http://127.0.0.1:${targetPort}/?token=${token}`));
1401
+ }
1402
+ return { ok: true, port: targetPort };
1403
+ }
1404
+
1405
+ log.warn('Gateway 重启后端口未就绪,请手动检查');
1406
+ return { ok: false, port: targetPort };
1407
+ }
1408
+
1302
1409
  function summarizeIssue(level, title, detail, solution, fixCmd = '') {
1303
1410
  return { level, title, detail, solution, fixCmd };
1304
1411
  }
@@ -2801,9 +2908,10 @@ async function showInteractiveMenu(existing) {
2801
2908
  console.log(` ${colors.yellow('9')}. 配置技能`);
2802
2909
  console.log(` ${colors.yellow('10')}. 重新安装`);
2803
2910
  console.log(` ${colors.yellow('11')}. 完全卸载`);
2911
+ console.log(` ${colors.yellow('12')}. 重置/更改端口`);
2804
2912
  console.log(` ${colors.yellow('0')}. 退出`);
2805
2913
 
2806
- const choice = await askQuestion('\n请输入选项 (0-11): ');
2914
+ const choice = await askQuestion('\n请输入选项 (0-12): ');
2807
2915
 
2808
2916
  switch (choice.trim()) {
2809
2917
  case '1':
@@ -2883,12 +2991,23 @@ async function showInteractiveMenu(existing) {
2883
2991
  process.exit(0);
2884
2992
  }
2885
2993
  break;
2994
+ case '12': {
2995
+ const portInput = await askQuestion('输入新端口号(留空自动分配): ');
2996
+ const requestedPort = portInput.trim() ? Number(portInput.trim()) : null;
2997
+ if (requestedPort && (isNaN(requestedPort) || requestedPort < 1024 || requestedPort > 65535)) {
2998
+ log.error('端口号无效,请输入 1024-65535 之间的数字');
2999
+ } else {
3000
+ await resetGatewayPort(cliName, requestedPort);
3001
+ }
3002
+ await waitForEnter('\n按回车返回菜单...');
3003
+ break;
3004
+ }
2886
3005
  case '0':
2887
3006
  case '':
2888
3007
  console.log(colors.gray('\n再见!'));
2889
3008
  process.exit(0);
2890
3009
  default:
2891
- log.warn('无效选项,请输入 0-11');
3010
+ log.warn('无效选项,请输入 0-12');
2892
3011
  }
2893
3012
  }
2894
3013
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclawsetup",
3
- "version": "2.8.10",
3
+ "version": "2.8.11",
4
4
  "description": "OpenClaw 安装向导 - 智能安装、诊断、自动修复",
5
5
  "type": "module",
6
6
  "bin": {