yymaxapi 1.0.28 → 1.0.31
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/yymaxapi.js +57 -23
- package/package.json +1 -1
package/bin/yymaxapi.js
CHANGED
|
@@ -841,20 +841,27 @@ async function selectDockerContainer() {
|
|
|
841
841
|
// 在 Docker 容器内执行命令
|
|
842
842
|
function execInDocker(containerId, cmd, options = {}) {
|
|
843
843
|
const escaped = cmd.replace(/'/g, "'\\''");
|
|
844
|
+
// 尝试 sh -c,fallback bash -lc
|
|
845
|
+
const r = safeExec(dockerCmd(`exec ${containerId} sh -c '${escaped}'`), { timeout: 30000, ...options });
|
|
846
|
+
if (r.ok) return r;
|
|
844
847
|
return safeExec(dockerCmd(`exec ${containerId} bash -lc '${escaped}'`), { timeout: 30000, ...options });
|
|
845
848
|
}
|
|
846
849
|
|
|
847
850
|
// 在 Docker 容器内异步执行命令(后台启动 gateway 等)
|
|
848
|
-
|
|
851
|
+
// shell 参数: 'sh -c' | 'bash -lc' | 'bash -c'
|
|
852
|
+
function spawnDetachedInDocker(containerId, cmd, shell = 'sh -c') {
|
|
849
853
|
try {
|
|
854
|
+
const shellParts = shell.split(' ');
|
|
855
|
+
const shellBin = shellParts[0];
|
|
856
|
+
const shellFlag = shellParts.slice(1).join(' ');
|
|
850
857
|
const prefix = _dockerNeedsSudo ? 'sudo' : 'docker';
|
|
851
858
|
const args = _dockerNeedsSudo
|
|
852
|
-
? ['-n', 'docker', 'exec', '-d', containerId,
|
|
853
|
-
: ['exec', '-d', containerId,
|
|
854
|
-
const child = spawn(prefix, args, {
|
|
859
|
+
? ['-n', 'docker', 'exec', '-d', containerId, shellBin, shellFlag, cmd]
|
|
860
|
+
: ['exec', '-d', containerId, shellBin, shellFlag, cmd];
|
|
861
|
+
const child = spawn(prefix, args.filter(Boolean), {
|
|
855
862
|
detached: true,
|
|
856
863
|
stdio: 'ignore',
|
|
857
|
-
env: { ...process.env
|
|
864
|
+
env: { ...process.env }
|
|
858
865
|
});
|
|
859
866
|
child.unref();
|
|
860
867
|
return true;
|
|
@@ -1058,7 +1065,7 @@ function cleanupAgentProcesses() {
|
|
|
1058
1065
|
if (detectGatewayEnv() === 'docker' && _selectedDockerContainer) {
|
|
1059
1066
|
try {
|
|
1060
1067
|
for (const name of ['openclaw', 'clawdbot', 'moltbot']) {
|
|
1061
|
-
safeExec(dockerCmd(`exec ${_selectedDockerContainer.id}
|
|
1068
|
+
safeExec(dockerCmd(`exec ${_selectedDockerContainer.id} sh -c "pkill -f '${name}.*agent' 2>/dev/null || true"`), { timeout: 10000 });
|
|
1062
1069
|
}
|
|
1063
1070
|
} catch { /* ignore */ }
|
|
1064
1071
|
}
|
|
@@ -1703,6 +1710,7 @@ async function tryAutoStartGateway(port, allowAutoDaemon) {
|
|
|
1703
1710
|
if (container.cli === 'node') {
|
|
1704
1711
|
dockerCmds.push(`node ${container.cliPath} gateway`);
|
|
1705
1712
|
} else {
|
|
1713
|
+
if (container.cliPath) dockerCmds.push(`${container.cliPath} gateway`);
|
|
1706
1714
|
dockerCmds.push(`${container.cli} gateway`);
|
|
1707
1715
|
}
|
|
1708
1716
|
for (const name of ['openclaw', 'clawdbot', 'moltbot']) {
|
|
@@ -1711,10 +1719,13 @@ async function tryAutoStartGateway(port, allowAutoDaemon) {
|
|
|
1711
1719
|
|
|
1712
1720
|
for (const cmd of [...new Set(dockerCmds)].filter(Boolean)) {
|
|
1713
1721
|
console.log(chalk.yellow(`⚠️ 尝试在容器内启动 Gateway: ${cmd}`));
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1722
|
+
// 尝试多种 shell
|
|
1723
|
+
for (const shell of ['sh -c', 'bash -lc', 'bash -c']) {
|
|
1724
|
+
if (spawnDetachedInDocker(container.id, cmd, shell)) {
|
|
1725
|
+
if (await waitForGateway(port, '127.0.0.1', 15000)) {
|
|
1726
|
+
console.log(chalk.green(`✅ Gateway 已在 Docker 容器 ${container.name} 内启动`));
|
|
1727
|
+
return { started: true, method: 'docker', container: container.name };
|
|
1728
|
+
}
|
|
1718
1729
|
}
|
|
1719
1730
|
}
|
|
1720
1731
|
}
|
|
@@ -2892,9 +2903,21 @@ async function testConnection(paths, args = {}) {
|
|
|
2892
2903
|
|
|
2893
2904
|
// 等待 Gateway 启动
|
|
2894
2905
|
const gwSpinner = ora({ text: '等待 Gateway 启动...', spinner: 'dots' }).start();
|
|
2895
|
-
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
2896
2906
|
|
|
2897
|
-
let gatewayRunning =
|
|
2907
|
+
let gatewayRunning = false;
|
|
2908
|
+
|
|
2909
|
+
if (restartOk) {
|
|
2910
|
+
// restartGateway 内部已经验证过端口可达,只需短暂确认
|
|
2911
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
2912
|
+
gatewayRunning = await waitForGateway(gatewayPort, '127.0.0.1', 5000);
|
|
2913
|
+
}
|
|
2914
|
+
|
|
2915
|
+
if (!gatewayRunning) {
|
|
2916
|
+
// restart 失败或未就绪,先等待更长时间(macOS LaunchAgent 启动较慢)
|
|
2917
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
2918
|
+
gatewayRunning = await waitForGateway(gatewayPort, '127.0.0.1', 20000);
|
|
2919
|
+
}
|
|
2920
|
+
|
|
2898
2921
|
if (!gatewayRunning) {
|
|
2899
2922
|
gwSpinner.text = '尝试自动启动 Gateway...';
|
|
2900
2923
|
const autoResult = await tryAutoStartGateway(gatewayPort, allowAutoDaemon);
|
|
@@ -3055,26 +3078,34 @@ async function restartGateway() {
|
|
|
3055
3078
|
|
|
3056
3079
|
const dockerCmds = [];
|
|
3057
3080
|
if (container.cli === 'node') {
|
|
3058
|
-
// 脚本路径模式(如 /opt/moltbot/moltbot.mjs)
|
|
3059
3081
|
dockerCmds.push(`node ${container.cliPath} gateway restart`);
|
|
3060
3082
|
} else {
|
|
3083
|
+
if (container.cliPath) dockerCmds.push(`${container.cliPath} gateway restart`);
|
|
3061
3084
|
dockerCmds.push(`${container.cli} gateway restart`);
|
|
3062
3085
|
}
|
|
3063
|
-
// 通用回退
|
|
3064
3086
|
for (const name of ['openclaw', 'clawdbot', 'moltbot']) {
|
|
3065
3087
|
dockerCmds.push(`${name} gateway restart`);
|
|
3066
3088
|
}
|
|
3067
3089
|
|
|
3090
|
+
// 每个命令尝试多种 shell(sh -c / bash -lc / bash -c)
|
|
3091
|
+
const shellVariants = ['sh -c', 'bash -lc', 'bash -c'];
|
|
3092
|
+
|
|
3068
3093
|
return new Promise((resolve) => {
|
|
3094
|
+
// 展开为 [cmd1+sh, cmd1+bash-lc, cmd1+bash-c, cmd2+sh, ...]
|
|
3095
|
+
const allAttempts = [];
|
|
3096
|
+
for (const cmd of [...new Set(dockerCmds)].filter(Boolean)) {
|
|
3097
|
+
for (const shell of shellVariants) {
|
|
3098
|
+
allAttempts.push(dockerCmd(`exec ${container.id} ${shell} "${cmd}"`));
|
|
3099
|
+
}
|
|
3100
|
+
}
|
|
3069
3101
|
let tried = 0;
|
|
3070
3102
|
const tryNext = () => {
|
|
3071
|
-
if (tried >=
|
|
3103
|
+
if (tried >= allAttempts.length) {
|
|
3072
3104
|
console.log(chalk.yellow('Docker 容器内 Gateway 重启失败,尝试本地重启...'));
|
|
3073
3105
|
restartGatewayNative().then(resolve);
|
|
3074
3106
|
return;
|
|
3075
3107
|
}
|
|
3076
|
-
const
|
|
3077
|
-
const fullCmd = dockerCmd(`exec ${container.id} bash -lc "${cmd}"`);
|
|
3108
|
+
const fullCmd = allAttempts[tried++];
|
|
3078
3109
|
exec(fullCmd, { timeout: 30000 }, (error) => {
|
|
3079
3110
|
if (error) {
|
|
3080
3111
|
tryNext();
|
|
@@ -3140,9 +3171,9 @@ async function forceRestartGateway(resolved, nodeInfo, useNode, env, gatewayPort
|
|
|
3140
3171
|
// 1. 杀掉容器内旧 Gateway 进程
|
|
3141
3172
|
try {
|
|
3142
3173
|
for (const name of ['openclaw', 'clawdbot', 'moltbot']) {
|
|
3143
|
-
safeExec(dockerCmd(`exec ${cid}
|
|
3174
|
+
safeExec(dockerCmd(`exec ${cid} sh -c "pkill -f '${name}.*gateway' 2>/dev/null || true"`), { timeout: 5000 });
|
|
3144
3175
|
}
|
|
3145
|
-
safeExec(dockerCmd(`exec ${cid}
|
|
3176
|
+
safeExec(dockerCmd(`exec ${cid} sh -c "lsof -ti :${gatewayPort} 2>/dev/null | xargs -r kill -9 2>/dev/null || true"`), { timeout: 5000 });
|
|
3146
3177
|
console.log(chalk.gray(' 已尝试清理容器内旧 Gateway 进程'));
|
|
3147
3178
|
} catch { /* ignore */ }
|
|
3148
3179
|
|
|
@@ -3153,6 +3184,7 @@ async function forceRestartGateway(resolved, nodeInfo, useNode, env, gatewayPort
|
|
|
3153
3184
|
if (_selectedDockerContainer.cli === 'node') {
|
|
3154
3185
|
dockerCmds.push(`node ${_selectedDockerContainer.cliPath} gateway`);
|
|
3155
3186
|
} else {
|
|
3187
|
+
if (_selectedDockerContainer.cliPath) dockerCmds.push(`${_selectedDockerContainer.cliPath} gateway`);
|
|
3156
3188
|
dockerCmds.push(`${_selectedDockerContainer.cli} gateway`);
|
|
3157
3189
|
}
|
|
3158
3190
|
for (const name of ['openclaw', 'clawdbot', 'moltbot']) {
|
|
@@ -3161,10 +3193,12 @@ async function forceRestartGateway(resolved, nodeInfo, useNode, env, gatewayPort
|
|
|
3161
3193
|
|
|
3162
3194
|
for (const cmd of [...new Set(dockerCmds)].filter(Boolean)) {
|
|
3163
3195
|
console.log(chalk.gray(` 尝试在容器内启动: ${cmd}`));
|
|
3164
|
-
|
|
3165
|
-
if (
|
|
3166
|
-
|
|
3167
|
-
|
|
3196
|
+
for (const shell of ['sh -c', 'bash -lc', 'bash -c']) {
|
|
3197
|
+
if (spawnDetachedInDocker(cid, cmd, shell)) {
|
|
3198
|
+
if (await waitForGateway(gatewayPort, '127.0.0.1', 12000)) {
|
|
3199
|
+
console.log(chalk.green(`✅ Gateway 已在 Docker 容器 ${cName} 内强制重启成功`));
|
|
3200
|
+
return true;
|
|
3201
|
+
}
|
|
3168
3202
|
}
|
|
3169
3203
|
}
|
|
3170
3204
|
}
|