Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions electron/utils/channel-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, statSync, rmSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
import { getOpenClawResolvedDir } from './paths';

const OPENCLAW_DIR = join(homedir(), '.openclaw');
const CONFIG_FILE = join(OPENCLAW_DIR, 'openclaw.json');
Expand Down Expand Up @@ -465,8 +466,6 @@ async function validateTelegramCredentials(
*/
export async function validateChannelConfig(channelType: string): Promise<ValidationResult> {
const { execSync } = await import('child_process');
const { join } = await import('path');
const { app } = await import('electron');

const result: ValidationResult = {
valid: true,
Expand All @@ -476,9 +475,7 @@ export async function validateChannelConfig(channelType: string): Promise<Valida

try {
// Get OpenClaw path
const openclawPath = app.isPackaged
? join(process.resourcesPath, 'openclaw')
: join(__dirname, '../../openclaw');
const openclawPath = getOpenClawResolvedDir();

// Run openclaw doctor command to validate config
const output = execSync(
Expand Down
18 changes: 17 additions & 1 deletion electron/utils/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import { app } from 'electron';
import { join } from 'path';
import { homedir } from 'os';
import { existsSync, mkdirSync, readFileSync } from 'fs';
import { existsSync, mkdirSync, readFileSync, realpathSync } from 'fs';
import { logger } from './logger';

/**
Expand Down Expand Up @@ -85,6 +85,22 @@ export function getOpenClawDir(): string {
return join(__dirname, '../../node_modules/openclaw');
}

/**
* Get OpenClaw package directory resolved to a real path.
* Useful when consumers need deterministic module resolution under pnpm symlinks.
*/
export function getOpenClawResolvedDir(): string {
const dir = getOpenClawDir();
if (!existsSync(dir)) {
return dir;
}
try {
return realpathSync(dir);
} catch {
return dir;
}
}

/**
* Get OpenClaw entry script path (openclaw.mjs)
*/
Expand Down
30 changes: 22 additions & 8 deletions electron/utils/whatsapp-login.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
import { join, resolve } from 'path';
import { dirname, join } from 'path';
import { homedir } from 'os';
import { createRequire } from 'module';
import { app } from 'electron';
import { EventEmitter } from 'events';
import { existsSync, mkdirSync, rmSync } from 'fs';
import { deflateSync } from 'zlib';
import { getOpenClawDir, getOpenClawResolvedDir } from './paths';

const require = createRequire(import.meta.url);

// Resolve paths to dependencies in openclaw/node_modules
const openclawPath = app.isPackaged
? join(process.resourcesPath, 'openclaw')
: resolve(__dirname, '../../openclaw');
// Resolve dependencies from OpenClaw package context (pnpm-safe)
const openclawPath = getOpenClawDir();
const openclawResolvedPath = getOpenClawResolvedDir();
const openclawRequire = createRequire(join(openclawResolvedPath, 'package.json'));

function resolveOpenClawPackageJson(packageName: string): string {
const specifier = `${packageName}/package.json`;
try {
return openclawRequire.resolve(specifier);
} catch (err) {
const reason = err instanceof Error ? err.message : String(err);
throw new Error(
`Failed to resolve "${packageName}" from OpenClaw context. ` +
`openclawPath=${openclawPath}, resolvedPath=${openclawResolvedPath}. ${reason}`,
{ cause: err }
);
}
}

const baileysPath = resolve(openclawPath, 'node_modules', '@whiskeysockets', 'baileys');
const qrcodeTerminalPath = resolve(openclawPath, 'node_modules', 'qrcode-terminal');
const baileysPath = dirname(resolveOpenClawPackageJson('@whiskeysockets/baileys'));
const qrcodeTerminalPath = dirname(resolveOpenClawPackageJson('qrcode-terminal'));

// Load Baileys dependencies dynamically
const {
Expand All @@ -29,7 +43,7 @@
const QRErrorCorrectLevelModule = require(join(qrcodeTerminalPath, 'vendor', 'QRCode', 'QRErrorCorrectLevel.js'));

// Types from Baileys (approximate since we don't have types for dynamic require)
type BaileysSocket = any;

Check warning on line 46 in electron/utils/whatsapp-login.ts

View workflow job for this annotation

GitHub Actions / check

Unexpected any. Specify a different type
type ConnectionState = {
connection: 'close' | 'open' | 'connecting';
lastDisconnect?: {
Expand Down Expand Up @@ -212,7 +226,7 @@

console.log(`[WhatsAppLogin] Connecting for ${accountId} at ${authDir} (Attempt ${this.retryCount + 1})`);

let pino: any;

Check warning on line 229 in electron/utils/whatsapp-login.ts

View workflow job for this annotation

GitHub Actions / check

Unexpected any. Specify a different type
try {
// Try to resolve pino from baileys context since it's a dependency of baileys
const baileysRequire = createRequire(join(baileysPath, 'package.json'));
Expand Down Expand Up @@ -268,7 +282,7 @@
}

if (connection === 'close') {
const error = (lastDisconnect?.error as any);

Check warning on line 285 in electron/utils/whatsapp-login.ts

View workflow job for this annotation

GitHub Actions / check

Unexpected any. Specify a different type
const shouldReconnect = error?.output?.statusCode !== DisconnectReason.loggedOut;
console.log('[WhatsAppLogin] Connection closed.',
'Reconnect:', shouldReconnect,
Expand Down
Loading