fix two clawx instances bug (#294)

This commit is contained in:
paisley
2026-03-04 21:20:21 +08:00
committed by GitHub
Unverified
parent fd58e721bd
commit 5ddb7d281d
2 changed files with 52 additions and 13 deletions

View File

@@ -126,28 +126,49 @@ const GATEWAY_FETCH_PRELOAD_SOURCE = `'use strict';
return _f.call(globalThis, input, init);
};
// Global monkey-patch for child_process to enforce windowsHide: true on Windows
// Global monkey-patch for child_process to enforce windowsHide: true on Windows.
// This prevents OpenClaw's tools (e.g. Terminal, Python) from flashing black
// command boxes during AI conversations, without triggering AVs.
//
// Node child_process signatures vary:
// spawn(cmd[, args][, options])
// exec(cmd[, options][, callback])
// execFile(file[, args][, options][, callback])
// *Sync variants omit the callback
//
// Strategy: scan arguments for the first plain-object (the options param).
// If found, set windowsHide on it. If absent, insert a new options object
// before any trailing callback so the signature stays valid.
if (process.platform === 'win32') {
try {
var cp = require('child_process');
if (!cp.__clawxPatched) {
cp.__clawxPatched = true;
['spawn', 'exec', 'execFile', 'spawnSync', 'execSync', 'execFileSync'].forEach(function(method) {
['spawn', 'exec', 'execFile', 'fork', 'spawnSync', 'execSync', 'execFileSync'].forEach(function(method) {
var original = cp[method];
if (typeof original === 'function') {
if (typeof original !== 'function') return;
cp[method] = function() {
var args = Array.prototype.slice.call(arguments);
var lastArg = args[args.length - 1];
if (lastArg && typeof lastArg === 'object' && !Array.isArray(lastArg)) {
lastArg.windowsHide = true;
var optIdx = -1;
for (var i = 1; i < args.length; i++) {
var a = args[i];
if (a && typeof a === 'object' && !Array.isArray(a)) {
optIdx = i;
break;
}
}
if (optIdx >= 0) {
args[optIdx].windowsHide = true;
} else {
args.push({ windowsHide: true });
var opts = { windowsHide: true };
if (typeof args[args.length - 1] === 'function') {
args.splice(args.length - 1, 0, opts);
} else {
args.push(opts);
}
}
return original.apply(this, args);
};
}
});
}
} catch (e) {

View File

@@ -37,6 +37,15 @@ import { ensureBuiltinSkillsInstalled } from '../utils/skill-config';
// set `"disable-hardware-acceleration": false` in the app config (future).
app.disableHardwareAcceleration();
// Prevent multiple instances of the app from running simultaneously.
// Without this, two instances each spawn their own gateway process on the
// same port, then each treats the other's gateway as "orphaned" and kills
// it — creating an infinite kill/restart loop on Windows.
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
app.quit();
}
// Global references
let mainWindow: BrowserWindow | null = null;
const gatewayManager = new GatewayManager();
@@ -242,6 +251,15 @@ async function initialize(): Promise<void> {
});
}
// When a second instance is launched, focus the existing window instead.
app.on('second-instance', () => {
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore();
mainWindow.show();
mainWindow.focus();
}
});
// Application lifecycle
app.whenReady().then(() => {
initialize();