From 9ef9d2602150707150dd66b68e5e395e01524a51 Mon Sep 17 00:00:00 2001 From: Mateusz Tymek Date: Sun, 4 Jan 2026 22:13:36 +0000 Subject: [PATCH] Cleanup --- main.js | 204 ++++++++++++++------------------ src/ProcessManager.ts | 267 ++++++++++++++++++------------------------ 2 files changed, 200 insertions(+), 271 deletions(-) diff --git a/main.js b/main.js index 40d60e1..3128343 100644 --- a/main.js +++ b/main.js @@ -416,7 +416,6 @@ var ProcessManager = class { this.state = "stopped"; this.lastError = null; this.earlyExitCode = null; - this.startupTimeout = null; this.settings = settings; this.workingDirectory = workingDirectory; this.projectDirectory = projectDirectory; @@ -447,134 +446,109 @@ var ProcessManager = class { this.setState("starting"); this.lastError = null; this.earlyExitCode = null; - try { - if (!this.projectDirectory) { - this.lastError = "Project directory (vault) not configured"; - console.error("[OpenCode Error]", this.lastError); - this.setState("error"); - return false; - } - const alreadyRunning = await this.checkServerHealth(); - if (alreadyRunning) { - console.log("OpenCode server already running on port", this.settings.port); - this.setState("running"); - return true; - } - console.log("[OpenCode] Starting server:", { - opencodePath: this.settings.opencodePath, - port: this.settings.port, - hostname: this.settings.hostname, + if (!this.projectDirectory) { + return this.setError("Project directory (vault) not configured"); + } + if (await this.checkServerHealth()) { + console.log("[OpenCode] Server already running on port", this.settings.port); + this.setState("running"); + return true; + } + console.log("[OpenCode] Starting server:", { + opencodePath: this.settings.opencodePath, + port: this.settings.port, + hostname: this.settings.hostname, + cwd: this.workingDirectory, + projectDirectory: this.projectDirectory + }); + this.process = (0, import_child_process.spawn)( + this.settings.opencodePath, + [ + "serve", + "--port", + this.settings.port.toString(), + "--hostname", + this.settings.hostname, + "--cors", + "app://obsidian.md" + ], + { cwd: this.workingDirectory, - projectDirectory: this.projectDirectory - }); - this.process = (0, import_child_process.spawn)( - this.settings.opencodePath, - [ - "serve", - "--port", - this.settings.port.toString(), - "--hostname", - this.settings.hostname, - "--cors", - "app://obsidian.md" - ], - { - cwd: this.workingDirectory, - env: { ...process.env }, - stdio: ["ignore", "pipe", "pipe"], - detached: false - } - ); - console.log("[OpenCode] Process spawned with PID:", this.process.pid); - (_a = this.process.stdout) == null ? void 0 : _a.on("data", (data) => { - console.log("[OpenCode]", data.toString().trim()); - }); - (_b = this.process.stderr) == null ? void 0 : _b.on("data", (data) => { - console.error("[OpenCode Error]", data.toString().trim()); - }); - this.process.on("exit", (code, signal) => { - console.log(`OpenCode process exited with code ${code}, signal ${signal}`); - this.process = null; - if (this.state === "starting" && code !== null && code !== 0) { - this.earlyExitCode = code; - } - if (this.state === "running") { - this.setState("stopped"); - } - }); - this.process.on("error", (err) => { - console.error("Failed to start OpenCode process:", err); - if (err.code === "ENOENT") { - this.lastError = `OpenCode executable not found at '${this.settings.opencodePath}'`; - } else { - this.lastError = `Failed to start OpenCode: ${err.message}`; - } - this.process = null; - this.setState("error"); - }); - const ready = await this.waitForServerOrExit(15e3); - if (ready) { - this.setState("running"); - return true; - } else { - if (this.state === "error") { - return false; - } - if (this.earlyExitCode !== null) { - this.lastError = `OpenCode process exited unexpectedly (exit code ${this.earlyExitCode})`; - } else if (!this.process) { - this.lastError = "OpenCode process exited before server became ready"; - } else { - this.lastError = "OpenCode server failed to start within timeout"; - } - this.stop(); - this.setState("error"); - return false; + env: { ...process.env }, + stdio: ["ignore", "pipe", "pipe"], + detached: false } - } catch (error) { - console.error("Error starting OpenCode:", error); - this.lastError = error instanceof Error ? error.message : String(error); - this.setState("error"); + ); + console.log("[OpenCode] Process spawned with PID:", this.process.pid); + (_a = this.process.stdout) == null ? void 0 : _a.on("data", (data) => { + console.log("[OpenCode]", data.toString().trim()); + }); + (_b = this.process.stderr) == null ? void 0 : _b.on("data", (data) => { + console.error("[OpenCode Error]", data.toString().trim()); + }); + this.process.on("exit", (code, signal) => { + console.log(`[OpenCode] Process exited with code ${code}, signal ${signal}`); + this.process = null; + if (this.state === "starting" && code !== null && code !== 0) { + this.earlyExitCode = code; + } + if (this.state === "running") { + this.setState("stopped"); + } + }); + this.process.on("error", (err) => { + console.error("[OpenCode] Failed to start process:", err); + this.process = null; + if (err.code === "ENOENT") { + this.setError(`Executable not found at '${this.settings.opencodePath}'`); + } else { + this.setError(`Failed to start: ${err.message}`); + } + }); + const ready = await this.waitForServerOrExit(15e3); + if (ready) { + this.setState("running"); + return true; + } + if (this.state === "error") { return false; } + this.stop(); + if (this.earlyExitCode !== null) { + return this.setError(`Process exited unexpectedly (exit code ${this.earlyExitCode})`); + } + if (!this.process) { + return this.setError("Process exited before server became ready"); + } + return this.setError("Server failed to start within timeout"); } stop() { - if (this.startupTimeout) { - clearTimeout(this.startupTimeout); - this.startupTimeout = null; - } - if (this.process) { - const proc = this.process; - const pid = proc.pid; - console.log("[OpenCode] Stopping process with PID:", pid); + if (!this.process) { this.setState("stopped"); - this.process = null; - try { - proc.kill("SIGTERM"); - console.log("[OpenCode] Sent SIGTERM to process"); - setTimeout(() => { - if (proc.exitCode === null && proc.signalCode === null) { - console.log("[OpenCode] Process still running after SIGTERM, sending SIGKILL"); - try { - proc.kill("SIGKILL"); - } catch (error) { - console.error("[OpenCode] Error sending SIGKILL:", error); - } - } else { - console.log("[OpenCode] Process exited with:", proc.exitCode, proc.signalCode); - } - }, 2e3); - } catch (error) { - console.error("[OpenCode] Error stopping process:", error); - } return; } + const proc = this.process; + console.log("[OpenCode] Stopping process with PID:", proc.pid); this.setState("stopped"); + this.process = null; + proc.kill("SIGTERM"); + setTimeout(() => { + if (proc.exitCode === null && proc.signalCode === null) { + console.log("[OpenCode] Process still running, sending SIGKILL"); + proc.kill("SIGKILL"); + } + }, 2e3); } setState(state) { this.state = state; this.onStateChange(state); } + setError(message) { + this.lastError = message; + console.error("[OpenCode Error]", message); + this.setState("error"); + return false; + } async checkServerHealth() { try { const response = await fetch(`${this.getUrl()}/global/health`, { @@ -591,7 +565,7 @@ var ProcessManager = class { const pollInterval = 500; while (Date.now() - startTime < timeoutMs) { if (!this.process) { - console.log("OpenCode process exited before server became ready"); + console.log("[OpenCode] Process exited before server became ready"); return false; } if (await this.checkServerHealth()) { diff --git a/src/ProcessManager.ts b/src/ProcessManager.ts index cbac113..6ab35b5 100644 --- a/src/ProcessManager.ts +++ b/src/ProcessManager.ts @@ -12,7 +12,6 @@ export class ProcessManager { private workingDirectory: string; private projectDirectory: string; private onStateChange: (state: ProcessState) => void; - private startupTimeout: NodeJS.Timeout | null = null; constructor( settings: OpenCodeSettings, @@ -44,7 +43,6 @@ export class ProcessManager { getUrl(): string { const baseUrl = `http://${this.settings.hostname}:${this.settings.port}`; - // Encode the project directory path as base64 for the URL const encodedPath = btoa(this.projectDirectory); return `${baseUrl}/${encodedPath}`; } @@ -58,171 +56,122 @@ export class ProcessManager { this.lastError = null; this.earlyExitCode = null; - try { - // Validate vault/project directory is set - if (!this.projectDirectory) { - this.lastError = "Project directory (vault) not configured"; - console.error("[OpenCode Error]", this.lastError); - this.setState("error"); - return false; - } + if (!this.projectDirectory) { + return this.setError("Project directory (vault) not configured"); + } - // Check if server is already running on this port - const alreadyRunning = await this.checkServerHealth(); - if (alreadyRunning) { - console.log("OpenCode server already running on port", this.settings.port); - this.setState("running"); - return true; - } + // Check if server is already running on this port + if (await this.checkServerHealth()) { + console.log("[OpenCode] Server already running on port", this.settings.port); + this.setState("running"); + return true; + } - // Start the opencode serve process (headless server, no browser) - // OpenCode is initialized with the vault directory as the project - console.log("[OpenCode] Starting server:", { - opencodePath: this.settings.opencodePath, - port: this.settings.port, - hostname: this.settings.hostname, + console.log("[OpenCode] Starting server:", { + opencodePath: this.settings.opencodePath, + port: this.settings.port, + hostname: this.settings.hostname, + cwd: this.workingDirectory, + projectDirectory: this.projectDirectory, + }); + + this.process = spawn( + this.settings.opencodePath, + [ + "serve", + "--port", + this.settings.port.toString(), + "--hostname", + this.settings.hostname, + "--cors", + "app://obsidian.md", + ], + { cwd: this.workingDirectory, - projectDirectory: this.projectDirectory, - }); - - this.process = spawn( - this.settings.opencodePath, - [ - "serve", - "--port", - this.settings.port.toString(), - "--hostname", - this.settings.hostname, - "--cors", - "app://obsidian.md", - ], - { - cwd: this.workingDirectory, - env: { ...process.env }, - stdio: ["ignore", "pipe", "pipe"], - detached: false, - } - ); - - console.log("[OpenCode] Process spawned with PID:", this.process.pid); - - // Handle process output - this.process.stdout?.on("data", (data) => { - console.log("[OpenCode]", data.toString().trim()); - }); - - this.process.stderr?.on("data", (data) => { - console.error("[OpenCode Error]", data.toString().trim()); - }); - - // Handle process exit - this.process.on("exit", (code, signal) => { - console.log(`OpenCode process exited with code ${code}, signal ${signal}`); - this.process = null; - - // Track early exit during startup for better error messages - if (this.state === "starting" && code !== null && code !== 0) { - this.earlyExitCode = code; - } - - // Only set stopped if we're in running state (not during startup) - if (this.state === "running") { - this.setState("stopped"); - } - }); - - this.process.on("error", (err: NodeJS.ErrnoException) => { - console.error("Failed to start OpenCode process:", err); - - // Provide user-friendly error messages for common errors - if (err.code === "ENOENT") { - this.lastError = `OpenCode executable not found at '${this.settings.opencodePath}'`; - } else { - this.lastError = `Failed to start OpenCode: ${err.message}`; - } - - this.process = null; - this.setState("error"); - }); - - // Wait for server to be ready, detecting early process exit - const ready = await this.waitForServerOrExit(15000); - if (ready) { - this.setState("running"); - return true; - } else { - // If already in error state (e.g., from spawn error event), don't overwrite - if (this.state === "error") { - return false; - } - - // Determine appropriate error message - if (this.earlyExitCode !== null) { - this.lastError = `OpenCode process exited unexpectedly (exit code ${this.earlyExitCode})`; - } else if (!this.process) { - this.lastError = "OpenCode process exited before server became ready"; - } else { - this.lastError = "OpenCode server failed to start within timeout"; - } - - this.stop(); - this.setState("error"); - return false; + env: { ...process.env }, + stdio: ["ignore", "pipe", "pipe"], + detached: false, } - } catch (error) { - console.error("Error starting OpenCode:", error); - this.lastError = error instanceof Error ? error.message : String(error); - this.setState("error"); + ); + + console.log("[OpenCode] Process spawned with PID:", this.process.pid); + + this.process.stdout?.on("data", (data) => { + console.log("[OpenCode]", data.toString().trim()); + }); + + this.process.stderr?.on("data", (data) => { + console.error("[OpenCode Error]", data.toString().trim()); + }); + + this.process.on("exit", (code, signal) => { + console.log(`[OpenCode] Process exited with code ${code}, signal ${signal}`); + this.process = null; + + if (this.state === "starting" && code !== null && code !== 0) { + this.earlyExitCode = code; + } + + if (this.state === "running") { + this.setState("stopped"); + } + }); + + this.process.on("error", (err: NodeJS.ErrnoException) => { + console.error("[OpenCode] Failed to start process:", err); + this.process = null; + + if (err.code === "ENOENT") { + this.setError(`Executable not found at '${this.settings.opencodePath}'`); + } else { + this.setError(`Failed to start: ${err.message}`); + } + }); + + // Wait for server to be ready + const ready = await this.waitForServerOrExit(15000); + if (ready) { + this.setState("running"); + return true; + } + + // If already in error state from spawn error event, don't overwrite + if (this.state === "error") { return false; } + + // Determine appropriate error message based on what happened + this.stop(); + if (this.earlyExitCode !== null) { + return this.setError(`Process exited unexpectedly (exit code ${this.earlyExitCode})`); + } + if (!this.process) { + return this.setError("Process exited before server became ready"); + } + return this.setError("Server failed to start within timeout"); } stop(): void { - if (this.startupTimeout) { - clearTimeout(this.startupTimeout); - this.startupTimeout = null; - } - - if (this.process) { - const proc = this.process; - const pid = proc.pid; - - console.log("[OpenCode] Stopping process with PID:", pid); - - // Set state to stopped first to prevent exit handler from interfering + if (!this.process) { this.setState("stopped"); - - // Now clear the process reference before killing - // This ensures the exit handler knows we initiated the stop - this.process = null; - - try { - // Try graceful shutdown first - proc.kill("SIGTERM"); - console.log("[OpenCode] Sent SIGTERM to process"); - - // Force kill after 2 seconds if still running - setTimeout(() => { - // Check if process has exited (exitCode or signalCode will be set) - if (proc.exitCode === null && proc.signalCode === null) { - console.log("[OpenCode] Process still running after SIGTERM, sending SIGKILL"); - try { - proc.kill("SIGKILL"); - } catch (error) { - console.error("[OpenCode] Error sending SIGKILL:", error); - } - } else { - console.log("[OpenCode] Process exited with:", proc.exitCode, proc.signalCode); - } - }, 2000); - } catch (error) { - console.error("[OpenCode] Error stopping process:", error); - } - return; } + const proc = this.process; + console.log("[OpenCode] Stopping process with PID:", proc.pid); + this.setState("stopped"); + this.process = null; + + proc.kill("SIGTERM"); + + // Force kill after 2 seconds if still running + setTimeout(() => { + if (proc.exitCode === null && proc.signalCode === null) { + console.log("[OpenCode] Process still running, sending SIGKILL"); + proc.kill("SIGKILL"); + } + }, 2000); } private setState(state: ProcessState): void { @@ -230,6 +179,13 @@ export class ProcessManager { this.onStateChange(state); } + private setError(message: string): false { + this.lastError = message; + console.error("[OpenCode Error]", message); + this.setState("error"); + return false; + } + private async checkServerHealth(): Promise { try { const response = await fetch(`${this.getUrl()}/global/health`, { @@ -247,12 +203,11 @@ export class ProcessManager { const pollInterval = 500; while (Date.now() - startTime < timeoutMs) { - // If process exited early, fail fast if (!this.process) { - console.log("OpenCode process exited before server became ready"); + console.log("[OpenCode] Process exited before server became ready"); return false; } - + if (await this.checkServerHealth()) { return true; }