-
-
- handleZoomPercentageChange(event.currentTarget.value)
- }
- onBlur={(event) => {
- const value = event.currentTarget.value;
- const numValue = Number(value);
- if (isNaN(numValue) || !isValidZoomPercentage(numValue)) {
- setZoomPercentage(
- zoomLevelToPercentage(zoomLevel).toString()
- );
- }
- }}
- rightSection={
-
- %
-
- }
- size="sm"
- w={80}
- styles={{
- input: {
- textAlign: 'center',
- },
- }}
- />
-
{
try {
await execa(packedPath, ['--unpack', unpackDir], {
- timeout: 30000,
+ timeout: 60000,
stdio: ['ignore', 'pipe', 'pipe'],
});
} catch (error) {
@@ -501,7 +501,7 @@ export class KoboldCppManager {
}
const result = await execa(launcherPath, ['--version'], {
- timeout: 10000,
+ timeout: 30000,
stdio: ['ignore', 'pipe', 'pipe'],
});
@@ -674,14 +674,6 @@ export class KoboldCppManager {
}>((resolve, reject) => {
readyResolve = resolve;
_readyReject = reject;
-
- setTimeout(() => {
- if (!isReady) {
- reject(
- new Error('Timeout waiting for KoboldCpp ready signal (30s)')
- );
- }
- }, 30000);
});
child.stdout?.on('data', (data) => {
diff --git a/src/main/managers/OpenWebUIManager.ts b/src/main/managers/OpenWebUIManager.ts
index 056f632..2d28812 100644
--- a/src/main/managers/OpenWebUIManager.ts
+++ b/src/main/managers/OpenWebUIManager.ts
@@ -1,8 +1,6 @@
import { spawn } from 'child_process';
import type { ChildProcess } from 'child_process';
import { join } from 'path';
-import { homedir } from 'os';
-import { access } from 'fs/promises';
import { LogManager } from './LogManager';
import { WindowManager } from './WindowManager';
@@ -55,16 +53,11 @@ export class OpenWebUIManager {
> {
const env = { ...process.env };
- const cargoPath = join(homedir(), '.cargo', 'bin');
-
- try {
- await access(cargoPath);
- env.PATH =
- process.platform === 'win32'
- ? `${cargoPath};${env.PATH}`
- : `${cargoPath}:${env.PATH}`;
- } catch {
- return env;
+ if (process.platform === 'win32') {
+ env.PYTHONIOENCODING = 'utf-8';
+ env.PYTHONLEGACYWINDOWSSTDIO = '1';
+ env.PYTHONUTF8 = '1';
+ env.CHCP = '65001';
}
return env;
@@ -73,13 +66,17 @@ export class OpenWebUIManager {
async isUvAvailable(): Promise {
try {
const env = await this.getUvEnvironment();
- const testProcess = spawn('uv', ['--version'], { stdio: 'pipe', env });
+ const testProcess = spawn('uv', ['--version'], {
+ stdio: 'pipe',
+ env,
+ shell: true,
+ });
return new Promise((resolve) => {
const timeout = setTimeout(() => {
testProcess.kill();
resolve(false);
- }, 5000);
+ }, 10000);
testProcess.on('exit', (code) => {
clearTimeout(timeout);
@@ -101,10 +98,18 @@ export class OpenWebUIManager {
env?: Record
): Promise {
const uvEnv = await this.getUvEnvironment();
+ const mergedEnv = { ...uvEnv, ...env };
+
+ if (process.platform === 'win32') {
+ mergedEnv.PYTHONIOENCODING = 'utf-8';
+ mergedEnv.PYTHONUTF8 = '1';
+ }
+
return spawn('uvx', args, {
stdio: ['pipe', 'pipe', 'pipe'],
detached: false,
- env: { ...uvEnv, ...env },
+ env: mergedEnv,
+ shell: true,
});
}
@@ -113,14 +118,24 @@ export class OpenWebUIManager {
return new Promise((resolve, reject) => {
const checkForOutput = (data: Buffer) => {
- const output = data.toString();
- if (output.includes(SERVER_READY_SIGNALS.OPENWEBUI)) {
- this.windowManager.sendKoboldOutput('Open WebUI is now running!');
- resolve();
+ try {
+ const output = data.toString('utf8');
+ if (output.includes(SERVER_READY_SIGNALS.OPENWEBUI)) {
+ this.windowManager.sendKoboldOutput('Open WebUI is now running!');
+ resolve();
- if (this.openWebUIProcess?.stdout) {
- this.openWebUIProcess.stdout.removeListener('data', checkForOutput);
+ if (this.openWebUIProcess?.stdout) {
+ this.openWebUIProcess.stdout.removeListener(
+ 'data',
+ checkForOutput
+ );
+ }
}
+ } catch (error) {
+ this.logManager.logError(
+ 'Error checking OpenWebUI output:',
+ error as Error
+ );
}
};
@@ -182,13 +197,29 @@ export class OpenWebUIManager {
if (this.openWebUIProcess.stdout) {
this.openWebUIProcess.stdout.on('data', (data: Buffer) => {
- this.windowManager.sendKoboldOutput(data.toString(), true);
+ try {
+ const output = data.toString('utf8');
+ this.windowManager.sendKoboldOutput(output, true);
+ } catch (error) {
+ this.logManager.logError(
+ 'Error processing stdout data:',
+ error as Error
+ );
+ }
});
}
if (this.openWebUIProcess.stderr) {
this.openWebUIProcess.stderr.on('data', (data: Buffer) => {
- this.windowManager.sendKoboldOutput(data.toString(), true);
+ try {
+ const output = data.toString('utf8');
+ this.windowManager.sendKoboldOutput(output, true);
+ } catch (error) {
+ this.logManager.logError(
+ 'Error processing stderr data:',
+ error as Error
+ );
+ }
});
}
diff --git a/src/main/managers/SillyTavernManager.ts b/src/main/managers/SillyTavernManager.ts
index 39b2bf8..c9b2e63 100644
--- a/src/main/managers/SillyTavernManager.ts
+++ b/src/main/managers/SillyTavernManager.ts
@@ -2,7 +2,6 @@ import { spawn } from 'child_process';
import { createServer, request, type Server } from 'http';
import { homedir } from 'os';
import { join } from 'path';
-import { access, readdir } from 'fs/promises';
import type { ChildProcess } from 'child_process';
import { LogManager } from './LogManager';
@@ -87,94 +86,12 @@ export class SillyTavernManager {
return join(dataRoot, 'default-user', 'settings.json');
}
- private async tryAddPathToEnv(
- env: Record,
- path: string
- ): Promise {
- const pathSeparator = process.platform === 'win32' ? ';' : ':';
- if (!env.PATH?.includes(path)) {
- env.PATH = `${path}${pathSeparator}${env.PATH}`;
- return true;
- }
- return false;
- }
-
- private async tryVersionManagerPath(
- basePath: string,
- env: Record
- ): Promise {
- try {
- await access(basePath);
- const versions = await readdir(basePath);
- if (versions.length > 0) {
- const latestVersion = versions.sort().pop();
- if (latestVersion) {
- const binSubPath = basePath.includes('fnm')
- ? join('installation', 'bin')
- : 'bin';
- const nodeBinPath = join(basePath, latestVersion, binSubPath);
-
- try {
- await access(nodeBinPath);
- return this.tryAddPathToEnv(env, nodeBinPath);
- } catch {
- return false;
- }
- }
- }
- } catch {
- return false;
- }
- return false;
- }
-
- private async getNodeEnvironment(): Promise<
- Record
- > {
- const env = { ...process.env };
-
- const versionManagerPaths = [
- join(homedir(), '.local', 'share', 'fnm', 'node-versions'),
- join(homedir(), '.nvm', 'versions', 'node'),
- join(homedir(), '.volta', 'tools', 'image', 'node'),
- join(homedir(), '.asdf', 'installs', 'nodejs'),
- ];
-
- const systemPaths: string[] = [];
- if (process.platform === 'darwin') {
- systemPaths.push('/opt/homebrew/bin', '/usr/local/bin');
- }
- if (process.platform === 'win32') {
- versionManagerPaths.push(
- join(homedir(), 'AppData', 'Local', 'fnm', 'node-versions'),
- join(homedir(), 'AppData', 'Roaming', 'nvm')
- );
- }
-
- for (const systemPath of systemPaths) {
- try {
- await access(systemPath);
- if (await this.tryAddPathToEnv(env, systemPath)) {
- return env;
- }
- } catch {
- continue;
- }
- }
-
- for (const versionPath of versionManagerPaths) {
- if (await this.tryVersionManagerPath(versionPath, env)) {
- return env;
- }
- }
-
- return env;
- }
-
async isNpxAvailable(): Promise {
try {
- const env = await this.getNodeEnvironment();
- const testProcess = spawn('npx', ['--version'], { stdio: 'pipe', env });
+ const testProcess = spawn('npx', ['--version'], {
+ stdio: 'pipe',
+ shell: true,
+ });
return new Promise((resolve) => {
const timeout = setTimeout(() => {
@@ -198,11 +115,10 @@ export class SillyTavernManager {
}
private async createNpxProcess(args: string[]): Promise {
- const env = await this.getNodeEnvironment();
return spawn('npx', args, {
stdio: ['pipe', 'pipe', 'pipe'],
detached: false,
- env,
+ shell: true,
});
}
diff --git a/src/main/managers/WindowManager.ts b/src/main/managers/WindowManager.ts
index 7e82857..ca772c5 100644
--- a/src/main/managers/WindowManager.ts
+++ b/src/main/managers/WindowManager.ts
@@ -72,6 +72,10 @@ export class WindowManager {
this.mainWindow = null;
});
+ if (!this.isDevelopment()) {
+ Menu.setApplicationMenu(null);
+ }
+
this.mainWindow.webContents.on('will-navigate', (event, navigationUrl) => {
const url = new URL(navigationUrl);
if (