Skip to content

fix(lsp): scope cache fallback by runtime provider#2354

Merged
bajrangCoder merged 2 commits into
mainfrom
fix/lsp-runtime-uri-scoping
Jun 21, 2026
Merged

fix(lsp): scope cache fallback by runtime provider#2354
bajrangCoder merged 2 commits into
mainfrom
fix/lsp-runtime-uri-scoping

Conversation

@bajrangCoder

Copy link
Copy Markdown
Member

No description provided.

@greptile-apps

greptile-apps Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR scopes the LSP client cache key by runtime provider ID and introduces a resolveUris hook on LspRuntimeProvider so each runtime can translate editor URIs (e.g. SAF content:// paths) into paths visible inside that runtime, rather than applying a single global cache-file fallback.

  • #resolveRuntimeTarget (new method in clientManager.ts) now selects the provider, calls resolveUris, and gates cache-key generation before any client is created, replacing the old #resolveDocumentUri fallback and moving provider selection out of #initializeClient.
  • builtinAlpine.resolveUris redirects inaccessible SAF and untitled documents to their cacheFile-backed file:// URI, returning scope: \"document\" so each such file gets its own isolated LSP client instance.
  • isBuiltinAlpineAccessible drops the untitled: scheme from its "directly accessible" list; untitled documents must now go through the explicit isUntitled && !!cacheDocumentUri branch in canHandle.

Confidence Score: 4/5

Safe to merge after addressing the canHandle/resolveUris contract gap in builtinAlpine.

The core refactor is well-structured and the new resolveUris hook is a clean abstraction. One concrete gap exists in builtinAlpine: canHandle approves untitled documents in file:// workspaces via the canUseRealPath branch (which looks at rootUri, not the document URI), but resolveUris will throw for the same documents if no cacheFile is present. The error is caught and LSP silently drops, making this a regression for untitled files opened inside a project folder without a cache file assigned. The rest of the changes — provider-scoped cache keys, scope-aware useWsFolders, removal of the global cache fallback — are correct.

src/cm/lsp/runtimes/builtinAlpine.ts — the canHandle method needs !isUntitled(context) added to its first branch.

Important Files Changed

Filename Overview
src/cm/lsp/clientManager.ts Major refactor: extracts #resolveRuntimeTarget to select the provider and resolve URIs before client init, scopes cache keys by runtime provider ID, and removes the LSP_SERVER_UNAVAILABLE error code. Logic is sound; no new blocking issues beyond the builtinAlpine edge case.
src/cm/lsp/runtimes/builtinAlpine.ts Adds resolveUris and canHandle rework; canHandle's first branch (canUseRealPath) can be true for untitled docs in file workspaces, but resolveUris will throw if no cacheFile exists, silently disabling LSP.
src/cm/lsp/runtimeProviders.ts Adds resolveUris to the validation loop in normalizeProvider; removes untitled scheme from isBuiltinAlpineAccessible — both changes are correct and consistent with the new provider design.
src/cm/lsp/types.ts Adds LspClientScope, LspRuntimeUriResolutionContext, LspRuntimeUriResolution, and originalDocumentUri to LspRuntimeContext; fixes originalRootUri nullability. All clean.
src/cm/lsp/index.ts Exports the three new public types from the package surface; straightforward addition with no issues.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant CM as LspClientManager
    participant RRT as #resolveRuntimeTarget
    participant RDU as #resolveDocumentUri
    participant SP as selectRuntimeProvider
    participant RP as LspRuntimeProvider
    participant EC as #ensureClient

    CM->>RRT: attach(server, uri, file, view)
    RRT->>RDU: normalizeDocumentUri(uri)
    RDU-->>RRT: "normalizedDocumentUri | null"
    RRT->>SP: selectRuntimeProvider(server, providerContext)
    SP->>RP: canHandle(server, context)
    RP-->>SP: boolean
    SP-->>RRT: "runtimeProvider | null"
    alt provider found
        RRT->>RP: resolveUris(server, resolutionContext)
        RP-->>RRT: "{documentUri, rootUri, scope} | null"
        RRT-->>CM: ResolvedRuntimeTarget
        CM->>EC: ensureClient(server, context, target)
        Note over EC: key = serverId@providerId::__document__::uri (scope=document) or pluginKey(serverId@providerId, rootUri) (scope=workspace)
        EC-->>CM: ClientState
    else no provider or no documentUri
        RRT-->>CM: null (warn, skip)
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant CM as LspClientManager
    participant RRT as #resolveRuntimeTarget
    participant RDU as #resolveDocumentUri
    participant SP as selectRuntimeProvider
    participant RP as LspRuntimeProvider
    participant EC as #ensureClient

    CM->>RRT: attach(server, uri, file, view)
    RRT->>RDU: normalizeDocumentUri(uri)
    RDU-->>RRT: "normalizedDocumentUri | null"
    RRT->>SP: selectRuntimeProvider(server, providerContext)
    SP->>RP: canHandle(server, context)
    RP-->>SP: boolean
    SP-->>RRT: "runtimeProvider | null"
    alt provider found
        RRT->>RP: resolveUris(server, resolutionContext)
        RP-->>RRT: "{documentUri, rootUri, scope} | null"
        RRT-->>CM: ResolvedRuntimeTarget
        CM->>EC: ensureClient(server, context, target)
        Note over EC: key = serverId@providerId::__document__::uri (scope=document) or pluginKey(serverId@providerId, rootUri) (scope=workspace)
        EC-->>CM: ClientState
    else no provider or no documentUri
        RRT-->>CM: null (warn, skip)
    end
Loading

Reviews (2): Last reviewed commit: "fix" | Re-trigger Greptile

Comment thread src/cm/lsp/runtimes/builtinAlpine.ts
Comment thread src/cm/lsp/runtimes/builtinAlpine.ts
Comment thread src/test/lspRuntime.tests.js Outdated
@bajrangCoder

This comment was marked as outdated.

@bajrangCoder bajrangCoder merged commit 25f86d7 into main Jun 21, 2026
10 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in The Code Board - Acode Jun 21, 2026
@bajrangCoder bajrangCoder deleted the fix/lsp-runtime-uri-scoping branch June 21, 2026 07:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant