diff --git a/src/frontends/tui/minimal.ts b/src/frontends/tui/minimal.ts index 4634f77..4310d31 100644 --- a/src/frontends/tui/minimal.ts +++ b/src/frontends/tui/minimal.ts @@ -52,7 +52,6 @@ export class MinimalTui { private totalUsage: TokenUsage = { inputTokens: 0, outputTokens: 0 }; private currentHint = ''; private lastLine = ''; - private backendPids: Map = new Map(); constructor(private config: MinimalTuiConfig) {} @@ -323,61 +322,62 @@ export class MinimalTui { } private async stopBackend(provider: string): Promise { - const pid = this.backendPids.get(provider); - if (!pid) { - return; // No tracked PID, process not started by us - } - try { - process.kill(pid, 'SIGTERM'); - // Wait up to 2 seconds for graceful shutdown - await new Promise((resolve) => { - const timeout = setTimeout(resolve, 2000); - const checkInterval = setInterval(() => { - try { - process.kill(pid, 0); // Check if process exists - } catch { - clearInterval(checkInterval); - clearTimeout(timeout); + const { exec } = await import('child_process'); + let serviceName: string; + switch (provider) { + case 'ollama': + serviceName = 'ollama.service'; + break; + case 'llamacpp': + serviceName = 'llama-server.service'; + break; + default: + return; + } + await new Promise((resolve, reject) => { + exec(`systemctl --user stop ${serviceName}`, (error) => { + if (error) { + reject(error); + } else { resolve(); } - }, 100); + }); }); - this.backendPids.delete(provider); } catch (error) { - // Process already dead or permission error - this.backendPids.delete(provider); + // Service might not exist or already stopped, ignore + console.log(`${colors.gray}Note: ${provider} service not managed by systemd${colors.reset}\n`); } } private async startBackend(provider: string, config: ModelConfig): Promise { try { - const { spawn } = await import('child_process'); - const args: string[] = []; - - let proc: ReturnType | undefined; - + const { exec } = await import('child_process'); + let serviceName: string; switch (provider) { case 'ollama': - proc = spawn('ollama', ['serve'], { detached: true, stdio: 'ignore' }); + serviceName = 'ollama.service'; break; case 'llamacpp': - args.push('--model', config.model); - args.push('--port', new URL(config.endpoint ?? 'http://localhost:8080').port || '8080'); - args.push('--host', '0.0.0.0'); - proc = spawn('llama-server', args, { detached: true, stdio: 'ignore' }); + serviceName = 'llama-server.service'; break; + default: + return; } + await new Promise((resolve, reject) => { + exec(`systemctl --user start ${serviceName}`, (error) => { + if (error) { + reject(error); + } else { + resolve(); + } + }); + }); - if (proc && proc.pid) { - proc.unref(); - this.backendPids.set(provider, proc.pid); - } - - // Wait briefly for the daemon to start + // Wait briefly for daemon to start await new Promise(resolve => setTimeout(resolve, 500)); } catch (error) { - console.log(`${colors.gray}Warning: Failed to start ${provider}: ${error instanceof Error ? error.message : String(error)}${colors.reset}\n`); + console.log(`${colors.gray}Warning: Failed to start ${provider} via systemd: ${error instanceof Error ? error.message : String(error)}${colors.reset}\n`); } }