fix(lsp): cleanup orphaned LSP servers on session.deleted (#676)

* fix(lsp): cleanup orphaned LSP servers on session.deleted

When parallel background agent tasks complete, their LSP servers (for
repos cloned to /tmp/) remain running until a 5-minute idle timeout.
This causes memory accumulation with heavy parallel Sisyphus usage,
potentially leading to OOM crashes.

This change adds cleanupTempDirectoryClients() to LSPServerManager
(matching the pattern used by SkillMcpManager.disconnectSession())
and calls it on session.deleted events.

The cleanup targets idle LSP clients (refCount=0) for temporary
directories (/tmp/, /var/folders/) where agent tasks clone repos.

* chore: retrigger CI checks
This commit is contained in:
Arthur Andrade
2026-01-10 23:45:38 -03:00
committed by GitHub
parent 65a6a702ec
commit 0c127879c0
3 changed files with 25 additions and 0 deletions

View File

@@ -63,6 +63,7 @@ import {
createSisyphusTask,
interactive_bash,
startTmuxCheck,
lspManager,
} from "./tools";
import { BackgroundManager } from "./features/background-agent";
import { SkillMcpManager } from "./features/skill-mcp-manager";
@@ -427,6 +428,7 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
}
if (sessionInfo?.id) {
await skillMcpManager.disconnectSession(sessionInfo.id);
await lspManager.cleanupTempDirectoryClients();
}
}

View File

@@ -10,8 +10,11 @@ import {
lsp_rename,
lsp_code_actions,
lsp_code_action_resolve,
lspManager,
} from "./lsp"
export { lspManager }
import {
ast_grep_search,
ast_grep_replace,

View File

@@ -182,6 +182,26 @@ class LSPServerManager {
this.cleanupInterval = null
}
}
async cleanupTempDirectoryClients(): Promise<void> {
const keysToRemove: string[] = []
for (const [key, managed] of this.clients.entries()) {
const isTempDir = key.startsWith("/tmp/") || key.startsWith("/var/folders/")
const isIdle = managed.refCount === 0
if (isTempDir && isIdle) {
keysToRemove.push(key)
}
}
for (const key of keysToRemove) {
const managed = this.clients.get(key)
if (managed) {
this.clients.delete(key)
try {
await managed.client.stop()
} catch {}
}
}
}
}
export const lspManager = LSPServerManager.getInstance()