yymaxapi 1.0.95 → 1.0.96

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/yymaxapi.js +67 -6
  2. package/package.json +1 -1
package/bin/yymaxapi.js CHANGED
@@ -639,6 +639,51 @@ function getGatewayListenOwner(port = 18789) {
639
639
  return ownerResult.output.trim().split(/\s+/)[0] || null;
640
640
  }
641
641
 
642
+ function getGatewayProcessSignature(port = 18789, environment = detectGatewayEnv()) {
643
+ if (!port) return '';
644
+
645
+ let result = null;
646
+
647
+ if (environment === 'docker') {
648
+ if (!_selectedDockerContainer?.id) return '';
649
+ result = safeExec(
650
+ dockerCmd(`exec ${_selectedDockerContainer.id} sh -c "lsof -ti :${port} 2>/dev/null"`),
651
+ { timeout: 3000 }
652
+ );
653
+ } else if (environment === 'wsl') {
654
+ result = safeExec(`wsl -- bash -c "lsof -ti :${port} 2>/dev/null"`, { timeout: 3000 });
655
+ } else if (process.platform === 'win32') {
656
+ result = safeExec(`netstat -ano | findstr ":${port}"`, { timeout: 3000 });
657
+ } else {
658
+ result = safeExec(`lsof -ti :${port} 2>/dev/null`, { timeout: 3000 });
659
+ }
660
+
661
+ const text = [result?.output, result?.stdout, result?.stderr]
662
+ .filter(Boolean)
663
+ .join('\n');
664
+ if (!text) return '';
665
+
666
+ const pids = process.platform === 'win32'
667
+ ? text
668
+ .split('\n')
669
+ .map(line => line.trim())
670
+ .filter(line => line.includes('LISTENING') && line.includes(`:${port}`))
671
+ .map(line => line.split(/\s+/).pop() || '')
672
+ .filter(pid => /^\d+$/.test(pid))
673
+ : text
674
+ .split('\n')
675
+ .map(line => line.trim())
676
+ .filter(pid => /^\d+$/.test(pid));
677
+
678
+ return [...new Set(pids)].sort().join(',');
679
+ }
680
+
681
+ function didGatewayProcessRestart({ portWasOpenBefore, beforeSignature, afterSignature }) {
682
+ if (!portWasOpenBefore) return true;
683
+ if (!beforeSignature || !afterSignature) return true;
684
+ return beforeSignature !== afterSignature;
685
+ }
686
+
642
687
  function getConfigPath() {
643
688
  const homeDir = os.homedir();
644
689
  const openclawStateDir = process.env.OPENCLAW_STATE_DIR || path.join(homeDir, '.openclaw');
@@ -5940,14 +5985,19 @@ async function restartGatewayDocker(gatewayPort, silent = false) {
5940
5985
 
5941
5986
  const cid = container.id;
5942
5987
  const shellVariants = ['sh -c', 'bash -lc', 'bash -c'];
5988
+ const portWasOpenBefore = await isPortOpen(gatewayPort, '127.0.0.1', 500);
5989
+ const beforeSignature = portWasOpenBefore ? getGatewayProcessSignature(gatewayPort, 'docker') : '';
5943
5990
 
5944
5991
  // 策略 A:exec restart 命令(短超时),然后端口探测
5945
5992
  for (const cmd of buildDockerInnerCmds(container, 'gateway restart')) {
5946
5993
  for (const shell of shellVariants) {
5947
5994
  safeExec(dockerCmd(`exec ${cid} ${shell} "${cmd}"`), { timeout: 8000 });
5948
5995
  if (await waitForGateway(gatewayPort, '127.0.0.1', 5000)) {
5949
- if (!silent) console.log(chalk.green(`✅ Gateway 已重启 (Docker: ${container.name})`));
5950
- return true;
5996
+ const afterSignature = getGatewayProcessSignature(gatewayPort, 'docker');
5997
+ if (didGatewayProcessRestart({ portWasOpenBefore, beforeSignature, afterSignature })) {
5998
+ if (!silent) console.log(chalk.green(`✅ Gateway 已重启 (Docker: ${container.name})`));
5999
+ return true;
6000
+ }
5951
6001
  }
5952
6002
  }
5953
6003
  }
@@ -5980,6 +6030,8 @@ async function restartGatewayWsl(gatewayPort, silent = false) {
5980
6030
  if (!silent) console.log(chalk.gray(' [检测] Gateway 运行在 WSL 中'));
5981
6031
  const wslCli = getWslCliBinary();
5982
6032
  const names = ['openclaw', 'clawdbot', 'moltbot'];
6033
+ const portWasOpenBefore = await isPortOpen(gatewayPort, '127.0.0.1', 500);
6034
+ const beforeSignature = portWasOpenBefore ? getGatewayProcessSignature(gatewayPort, 'wsl') : '';
5983
6035
 
5984
6036
  // 构建 WSL 重启命令
5985
6037
  const wslRestartCmds = [];
@@ -5990,8 +6042,11 @@ async function restartGatewayWsl(gatewayPort, silent = false) {
5990
6042
  for (const cmd of wslRestartCmds) {
5991
6043
  safeExec(cmd, { timeout: 8000 });
5992
6044
  if (await waitForGateway(gatewayPort, '127.0.0.1', 5000)) {
5993
- if (!silent) console.log(chalk.green('✅ Gateway 已重启 (WSL)'));
5994
- return true;
6045
+ const afterSignature = getGatewayProcessSignature(gatewayPort, 'wsl');
6046
+ if (didGatewayProcessRestart({ portWasOpenBefore, beforeSignature, afterSignature })) {
6047
+ if (!silent) console.log(chalk.green('✅ Gateway 已重启 (WSL)'));
6048
+ return true;
6049
+ }
5995
6050
  }
5996
6051
  }
5997
6052
 
@@ -6030,6 +6085,8 @@ async function restartGatewayNative(silent = false) {
6030
6085
  const configPaths = getConfigPath();
6031
6086
  const gwConfig = readConfig(configPaths.openclawConfig);
6032
6087
  const gatewayPort = gwConfig?.gateway?.port || 18789;
6088
+ const portWasOpenBefore = await isPortOpen(gatewayPort, '127.0.0.1', 500);
6089
+ const beforeSignature = portWasOpenBefore ? getGatewayProcessSignature(gatewayPort, 'native') : '';
6033
6090
 
6034
6091
  // 策略 A:尝试 exec "gateway restart"(短超时),然后端口探测
6035
6092
  const restartCmds = buildGatewayCommands(resolved, nodeInfo, useNode, 'restart');
@@ -6037,8 +6094,12 @@ async function restartGatewayNative(silent = false) {
6037
6094
  // 只尝试第一条(最精确的路径),避免逐条超时累积
6038
6095
  safeExec(restartCmds[0], { timeout: 8000, env });
6039
6096
  if (await waitForGateway(gatewayPort, '127.0.0.1', 5000)) {
6040
- if (!silent) console.log(chalk.green(`✅ Gateway 已重启`));
6041
- return true;
6097
+ const afterSignature = getGatewayProcessSignature(gatewayPort, 'native');
6098
+ if (didGatewayProcessRestart({ portWasOpenBefore, beforeSignature, afterSignature })) {
6099
+ if (!silent) console.log(chalk.green(`✅ Gateway 已重启`));
6100
+ return true;
6101
+ }
6102
+ if (!silent) console.log(chalk.gray(' 检测到 Gateway 监听进程未变化,继续执行强制重启...'));
6042
6103
  }
6043
6104
  }
6044
6105
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yymaxapi",
3
- "version": "1.0.95",
3
+ "version": "1.0.96",
4
4
  "description": "跨平台 OpenClaw/Clawdbot 配置管理工具 - 管理中转地址、模型切换、API Keys、测速优化",
5
5
  "main": "bin/yymaxapi.js",
6
6
  "bin": {