fix: remove cached mcpClient in diagnostic tracking to prevent stale references (#727)
* fix: remove cached mcpClient in diagnostic tracking to prevent stale references Resolves TODO comment about not caching the connected mcpClient since it can change. Changes: - Remove cached mcpClient field from DiagnosticTrackingService - Add currentMcpClients storage to track active clients - Update beforeFileEdited, getNewDiagnostics, and ensureFileOpened to accept client parameter - Add backward-compatible methods to maintain existing API - Update all callers to use new methods - Add comprehensive test coverage This prevents using stale MCP client references during reconnections, making diagnostic tracking more reliable. Fixes #TODO * docs: add my contributions section to README Add fork-specific section highlighting: - Diagnostic tracking enhancement (PR #727) - Technical skills demonstrated - Links to original project and my work - Professional contribution showcase * revert: remove README.md contributions section to comply with reviewer request - Remove 'My Fork & Contributions' section from README.md - Keep README.md focused on original project documentation - Maintain clean, project-focused README as requested by reviewer
This commit is contained in:
committed by
GitHub
parent
b786b765f0
commit
2c98be7002
@@ -32,7 +32,7 @@ export class DiagnosticTrackingService {
|
||||
private baseline: Map<string, Diagnostic[]> = new Map()
|
||||
|
||||
private initialized = false
|
||||
private mcpClient: MCPServerConnection | undefined
|
||||
private currentMcpClients: MCPServerConnection[] = []
|
||||
|
||||
// Track when files were last processed/fetched
|
||||
private lastProcessedTimestamps: Map<string, number> = new Map()
|
||||
@@ -48,18 +48,17 @@ export class DiagnosticTrackingService {
|
||||
return DiagnosticTrackingService.instance
|
||||
}
|
||||
|
||||
initialize(mcpClient: MCPServerConnection) {
|
||||
initialize() {
|
||||
if (this.initialized) {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Do not cache the connected mcpClient since it can change.
|
||||
this.mcpClient = mcpClient
|
||||
this.initialized = true
|
||||
}
|
||||
|
||||
async shutdown(): Promise<void> {
|
||||
this.initialized = false
|
||||
this.currentMcpClients = []
|
||||
this.baseline.clear()
|
||||
this.rightFileDiagnosticsState.clear()
|
||||
this.lastProcessedTimestamps.clear()
|
||||
@@ -75,6 +74,46 @@ export class DiagnosticTrackingService {
|
||||
this.lastProcessedTimestamps.clear()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current IDE client from stored MCP clients
|
||||
*/
|
||||
private getCurrentIdeClient(): MCPServerConnection | undefined {
|
||||
return getConnectedIdeClient(this.currentMcpClients)
|
||||
}
|
||||
|
||||
/**
|
||||
* Backward-compatible method that uses stored IDE client
|
||||
*/
|
||||
async beforeFileEditedCompat(filePath: string): Promise<void> {
|
||||
const ideClient = this.getCurrentIdeClient()
|
||||
if (!ideClient) {
|
||||
return
|
||||
}
|
||||
return await this.beforeFileEdited(filePath, ideClient)
|
||||
}
|
||||
|
||||
/**
|
||||
* Backward-compatible method that uses stored IDE client
|
||||
*/
|
||||
async getNewDiagnosticsCompat(): Promise<DiagnosticFile[]> {
|
||||
const ideClient = this.getCurrentIdeClient()
|
||||
if (!ideClient) {
|
||||
return []
|
||||
}
|
||||
return await this.getNewDiagnostics(ideClient)
|
||||
}
|
||||
|
||||
/**
|
||||
* Backward-compatible method that uses stored IDE client
|
||||
*/
|
||||
async ensureFileOpenedCompat(fileUri: string): Promise<void> {
|
||||
const ideClient = this.getCurrentIdeClient()
|
||||
if (!ideClient) {
|
||||
return
|
||||
}
|
||||
return await this.ensureFileOpened(fileUri, ideClient)
|
||||
}
|
||||
|
||||
private normalizeFileUri(fileUri: string): string {
|
||||
// Remove our protocol prefixes
|
||||
const protocolPrefixes = [
|
||||
@@ -100,11 +139,11 @@ export class DiagnosticTrackingService {
|
||||
* Ensure a file is opened in the IDE before processing.
|
||||
* This is important for language services like diagnostics to work properly.
|
||||
*/
|
||||
async ensureFileOpened(fileUri: string): Promise<void> {
|
||||
async ensureFileOpened(fileUri: string, mcpClient: MCPServerConnection): Promise<void> {
|
||||
if (
|
||||
!this.initialized ||
|
||||
!this.mcpClient ||
|
||||
this.mcpClient.type !== 'connected'
|
||||
!mcpClient ||
|
||||
mcpClient.type !== 'connected'
|
||||
) {
|
||||
return
|
||||
}
|
||||
@@ -121,7 +160,7 @@ export class DiagnosticTrackingService {
|
||||
selectToEndOfLine: false,
|
||||
makeFrontmost: false,
|
||||
},
|
||||
this.mcpClient,
|
||||
mcpClient,
|
||||
)
|
||||
} catch (error) {
|
||||
logError(error as Error)
|
||||
@@ -132,11 +171,11 @@ export class DiagnosticTrackingService {
|
||||
* Capture baseline diagnostics for a specific file before editing.
|
||||
* This is called before editing a file to ensure we have a baseline to compare against.
|
||||
*/
|
||||
async beforeFileEdited(filePath: string): Promise<void> {
|
||||
async beforeFileEdited(filePath: string, mcpClient: MCPServerConnection): Promise<void> {
|
||||
if (
|
||||
!this.initialized ||
|
||||
!this.mcpClient ||
|
||||
this.mcpClient.type !== 'connected'
|
||||
!mcpClient ||
|
||||
mcpClient.type !== 'connected'
|
||||
) {
|
||||
return
|
||||
}
|
||||
@@ -147,7 +186,7 @@ export class DiagnosticTrackingService {
|
||||
const result = await callIdeRpc(
|
||||
'getDiagnostics',
|
||||
{ uri: `file://${filePath}` },
|
||||
this.mcpClient,
|
||||
mcpClient,
|
||||
)
|
||||
const diagnosticFile = this.parseDiagnosticResult(result)[0]
|
||||
if (diagnosticFile) {
|
||||
@@ -185,11 +224,11 @@ export class DiagnosticTrackingService {
|
||||
* Get new diagnostics from file://, _claude_fs_right, and _claude_fs_ URIs that aren't in the baseline.
|
||||
* Only processes diagnostics for files that have been edited.
|
||||
*/
|
||||
async getNewDiagnostics(): Promise<DiagnosticFile[]> {
|
||||
async getNewDiagnostics(mcpClient: MCPServerConnection): Promise<DiagnosticFile[]> {
|
||||
if (
|
||||
!this.initialized ||
|
||||
!this.mcpClient ||
|
||||
this.mcpClient.type !== 'connected'
|
||||
!mcpClient ||
|
||||
mcpClient.type !== 'connected'
|
||||
) {
|
||||
return []
|
||||
}
|
||||
@@ -200,7 +239,7 @@ export class DiagnosticTrackingService {
|
||||
const result = await callIdeRpc(
|
||||
'getDiagnostics',
|
||||
{}, // Empty params fetches all diagnostics
|
||||
this.mcpClient,
|
||||
mcpClient,
|
||||
)
|
||||
allDiagnosticFiles = this.parseDiagnosticResult(result)
|
||||
} catch (_error) {
|
||||
@@ -328,13 +367,16 @@ export class DiagnosticTrackingService {
|
||||
* @param shouldQuery Whether a query is actually being made (not just a command)
|
||||
*/
|
||||
async handleQueryStart(clients: MCPServerConnection[]): Promise<void> {
|
||||
// Store the current MCP clients for later use
|
||||
this.currentMcpClients = clients
|
||||
|
||||
// Only proceed if we should query and have clients
|
||||
if (!this.initialized) {
|
||||
// Find the connected IDE client
|
||||
const connectedIdeClient = getConnectedIdeClient(clients)
|
||||
|
||||
if (connectedIdeClient) {
|
||||
this.initialize(connectedIdeClient)
|
||||
this.initialize()
|
||||
}
|
||||
} else {
|
||||
// Reset diagnostic tracking for new query loops
|
||||
|
||||
Reference in New Issue
Block a user