Skip to content

Commit c440e95

Browse files
authored
chore(product): fix link in app (#22)
1 parent fa22a17 commit c440e95

5 files changed

Lines changed: 52 additions & 5 deletions

File tree

electron-builder.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,12 @@ mac:
6262
NSCameraUsageDescription: ClawX requires camera access for video features
6363

6464
dmg:
65-
# background: resources/dmg-background.png
65+
background: resources/dmg-background.png
6666
icon: resources/icons/icon.icns
6767
iconSize: 100
68+
window:
69+
width: 540
70+
height: 380
6871
contents:
6972
- type: file
7073
x: 130

electron/gateway/manager.ts

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,39 @@ const DEFAULT_RECONNECT_CONFIG: ReconnectConfig = {
6363
maxDelay: 30000,
6464
};
6565

66+
/**
67+
* Get the Node.js-compatible executable path for spawning child processes.
68+
*
69+
* On macOS in packaged mode, using `process.execPath` directly causes the
70+
* child process to appear as a separate dock icon (named "exec") because the
71+
* binary lives inside a `.app` bundle that macOS treats as a GUI application.
72+
*
73+
* To avoid this, we resolve the Electron Helper binary which has
74+
* `LSUIElement` set in its Info.plist, preventing dock icon creation.
75+
* Falls back to `process.execPath` if the Helper binary is not found.
76+
*/
77+
function getNodeExecutablePath(): string {
78+
if (process.platform === 'darwin' && app.isPackaged) {
79+
// Electron Helper binary lives at:
80+
// <App>.app/Contents/Frameworks/<ProductName> Helper.app/Contents/MacOS/<ProductName> Helper
81+
const appName = app.getName();
82+
const helperName = `${appName} Helper`;
83+
const helperPath = path.join(
84+
path.dirname(process.execPath), // .../Contents/MacOS
85+
'../Frameworks',
86+
`${helperName}.app`,
87+
'Contents/MacOS',
88+
helperName,
89+
);
90+
if (existsSync(helperPath)) {
91+
logger.info(`Using Electron Helper binary to avoid dock icon: ${helperPath}`);
92+
return helperPath;
93+
}
94+
logger.warn(`Electron Helper binary not found at ${helperPath}, falling back to process.execPath`);
95+
}
96+
return process.execPath;
97+
}
98+
6699
/**
67100
* Gateway Manager
68101
* Handles starting, stopping, and communicating with the OpenClaw Gateway
@@ -377,11 +410,13 @@ export class GatewayManager extends EventEmitter {
377410
const gatewayArgs = ['gateway', '--port', String(this.status.port), '--token', gatewayToken, '--dev', '--allow-unconfigured'];
378411

379412
if (app.isPackaged) {
380-
// Production: always use Electron binary as Node.js via ELECTRON_RUN_AS_NODE
413+
// Production: use Electron binary as Node.js via ELECTRON_RUN_AS_NODE
414+
// On macOS, use the Electron Helper binary to avoid extra dock icons
381415
if (existsSync(entryScript)) {
382-
command = process.execPath;
416+
command = getNodeExecutablePath();
383417
args = [entryScript, ...gatewayArgs];
384418
logger.info('Starting Gateway in PACKAGED mode (ELECTRON_RUN_AS_NODE)');
419+
logger.info(`Using executable: ${command}`);
385420
} else {
386421
const errMsg = `OpenClaw entry script not found at: ${entryScript}`;
387422
logger.error(errMsg);
@@ -449,6 +484,15 @@ export class GatewayManager extends EventEmitter {
449484
// Critical: In packaged mode, make Electron binary act as Node.js
450485
if (app.isPackaged) {
451486
spawnEnv['ELECTRON_RUN_AS_NODE'] = '1';
487+
// Prevent OpenClaw entry.ts from respawning itself (which would create
488+
// another child process and a second "exec" dock icon on macOS)
489+
spawnEnv['OPENCLAW_NO_RESPAWN'] = '1';
490+
// Pre-set the NODE_OPTIONS that entry.ts would have added via respawn
491+
const existingNodeOpts = spawnEnv['NODE_OPTIONS'] ?? '';
492+
if (!existingNodeOpts.includes('--disable-warning=ExperimentalWarning') &&
493+
!existingNodeOpts.includes('--no-warnings')) {
494+
spawnEnv['NODE_OPTIONS'] = `${existingNodeOpts} --disable-warning=ExperimentalWarning`.trim();
495+
}
452496
}
453497

454498
this.process = spawn(command, args, {

electron/main/menu.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ export function createMenu(): void {
176176
{
177177
label: 'Documentation',
178178
click: async () => {
179-
await shell.openExternal('https://docs.clawx.app');
179+
await shell.openExternal('https://clawx.dev');
180180
},
181181
},
182182
{

resources/dmg-background.png

5.62 KB
Loading

src/pages/Settings/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ export function Settings() {
347347
<Button
348348
variant="link"
349349
className="h-auto p-0"
350-
onClick={() => window.electron.openExternal('https://docs.clawx.app')}
350+
onClick={() => window.electron.openExternal('https://clawx.dev')}
351351
>
352352
Documentation
353353
</Button>

0 commit comments

Comments
 (0)