diff --git a/index.ts b/index.ts index 6cb5196..8c301ca 100644 --- a/index.ts +++ b/index.ts @@ -6,11 +6,58 @@ import { log } from "./logger.js" log("Plugin module loaded") +// ============================================================================= +// Global mutex — prevents double startup (server + client both load plugins) +// ============================================================================= + +const LOCK_FILE = "/tmp/opencode-matrix-plugin.lock" + +function tryAcquireLock(): boolean { + try { + // Check if an existing lock is stale (process no longer running) + if (fs.existsSync(LOCK_FILE)) { + const existingPid = parseInt(fs.readFileSync(LOCK_FILE, "utf-8").trim(), 10) + if (existingPid && existingPid !== process.pid) { + try { + process.kill(existingPid, 0) // throws if process doesn't exist + } catch { + // Process dead, remove stale lock + fs.unlinkSync(LOCK_FILE) + } + } else if (existingPid === process.pid) { + // Same process re-entering (shouldn't happen, but be safe) + return false + } else { + return false // Valid lock held by another process + } + } + fs.writeFileSync(LOCK_FILE, String(process.pid), { mode: 0o644 }) + return true + } catch { + return false + } +} + +function releaseLock(): void { + try { + fs.unlinkSync(LOCK_FILE) + } catch { + // ignore + } +} + // ============================================================================= // Plugin Setup // ============================================================================= async function runPlugin(ctx: any, options: any) { + // Acquire global lock — only one instance (server or client) starts the bot + const locked = tryAcquireLock() + if (!locked) { + log("Another instance already running (lock held), skipping bot startup") + return () => {} + } + const eventController = new AbortController() let cleanup: (() => void) | undefined @@ -213,15 +260,15 @@ async function runPlugin(ctx: any, options: any) { log("Plugin cleaning up...") eventController.abort() matrix.stop() + releaseLock() } return cleanup } catch (err) { fs.appendFileSync("/tmp/opencode-matrix-plugin/setup-error.log", `[${new Date().toISOString()}] ${String(err)}\n`) log(`Setup error: ${String(err)}`) - return () => { - cleanup?.() - } + releaseLock() + return () => {} } }