Skip to content

feat(lsp) Adds SFTP URI resolution to the runtime provider for LSP workspaces. - #2703

Open
gat0sy wants to merge 5 commits into
Acode-Foundation:mainfrom
gat0sy:feat/sftp-remote-lsp
Open

feat(lsp) Adds SFTP URI resolution to the runtime provider for LSP workspaces.#2703
gat0sy wants to merge 5 commits into
Acode-Foundation:mainfrom
gat0sy:feat/sftp-remote-lsp

Conversation

@gat0sy

@gat0sy gat0sy commented Aug 8, 2026

Copy link
Copy Markdown

This PR is based on PR #2702

gat0sy added 5 commits August 7, 2026 21:41
LspToPosition threw range error on format error.
We attempt to fix it here with by clamping so we get the correct line count between the client and server.

applyTextEdit as also been extracted so both transport and client manager can import it from the helper.
go to def and similar fonction have been added,
a new interceptFileLink method has been created to solve an FileUriExposedException you may get if taping the signature link on the hover.

if the link is a website, it skips and let the normal behavior occur ( open a web browser page )
if the link is a file, it modifies the uri so the tap behave like a go to instead of crashing the whole app.
There are notably also some fixes for code actions, rename...ect, now they use the new lspPostionToOffset that uses clamping
…actions menu

Added resolveContentUriForFileUri() to map LSP file:// responses back to
content:// and sftp:// URIs via addedFolder matching

Refactor editorManager displayFile/openFile to resolve URIs before
opening, enabling cross-workspace go-to-definition and references

Added SFTP path-aware root URI resolution for remote workspace context

Replace selection menu code-actions button with full LSP actions menu
(definition, declaration, implementation, type-definition, references,
rename, code-actions) with single-item auto-execution
Added sftpRemote.ts runtime provider that translates sftp:// URIs to

 file:// before sending to LSP servers, stripping host/credentials

 Register sftpRemoteRuntimeProvider in registerBuiltins.ts
Delegate transport to external-websocket provider since SFTP LSP
connections are handled via WebSocket tunnel
@greptile-apps

greptile-apps Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds SFTP-aware LSP URI resolution and navigation, expands the selection menu with definition-related actions, handles server-pushed workspace edits, and consolidates custom-server configuration.

  • Registers an SFTP runtime provider and maps remote paths to LSP file URIs.
  • Adds definition, declaration, implementation, and type-definition navigation.
  • Adds workspace/applyEdit handling and shared text-edit utilities.
  • Resolves LSP file URIs back to SAF, SFTP, or local editor files.
  • Introduces an idle grace period and a consolidated LSP custom-server dialog.

Confidence Score: 0/5

The PR is not safe to merge until workspace edits are scoped to their originating client and root and SFTP client identity and URI encoding are preserved.

Server-pushed edits can target unrelated files and use another client's synchronization state, while distinct SFTP connections can collide in the client cache and valid remote paths can become malformed LSP URIs.

Files Needing Attention: src/cm/lsp/transport.ts, src/cm/lsp/runtimes/sftpRemote.ts, src/components/referencesPanel/utils.js

Security Review

The new workspace/applyEdit handler trusts server-provided target URIs without enforcing the active workspace boundary. Because external WebSocket LSP servers are supported, a compromised peer can request edits to unrelated app-accessible documents.

How this was verified: The request path was traced from the WebSocket handler through workspace.displayFile to the unrestricted general-purpose file opener.

Important Files Changed

Filename Overview
src/cm/lsp/runtimes/sftpRemote.ts Adds SFTP runtime delegation, but strips connection identity from cache-key inputs and emits unencoded file URIs.
src/cm/lsp/transport.ts Adds workspace/applyEdit support without workspace scoping and selects plugins without identifying the requesting client.
src/cm/lsp/textEditUtils.ts Centralizes position conversion and text-edit application; correctness depends on receiving the matching client plugin.
src/lib/editorManager.js Adds SFTP root matching and file-URI resolution used by LSP navigation and workspace edits.
src/components/referencesPanel/utils.js Maps file URIs back to available SAF, SFTP, and local roots, with inconsistent SFTP path encoding.
src/cm/lsp/definition.ts Implements definition-family requests and reuses the references panel for multiple destinations.
src/settings/lspSettings.js Consolidates custom LSP server setup into a multi-field transport-aware dialog.

Sequence Diagram

sequenceDiagram
    participant SFTP as SFTP Workspace
    participant Runtime as sftpRemote Provider
    participant Manager as LspClientManager
    participant LSP as WebSocket LSP Server
    participant Workspace as AcodeWorkspace
    participant Editor as EditorView
    SFTP->>Runtime: sftp://authority/path
    Runtime->>Manager: file:///path root and document URI
    Manager->>LSP: initialize and didOpen
    LSP->>Manager: workspace/applyEdit(uri, edits)
    Manager->>Workspace: displayFile(uri)
    Workspace->>Editor: open and dispatch edits
Loading

Reviews (1): Last reviewed commit: "feat(lsp): add SFTP remote runtime provi..." | Re-trigger Greptile

Comment thread src/cm/lsp/transport.ts
Comment on lines +199 to +207
for (const uri of uris) {
const edits = changesByUri[uri];
if (!edits.length) continue;

let view = workspace.getFile(uri)?.getView();
if (!view) {
try {
view = await workspace.displayFile(uri);
} catch (error) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Workspace edit escapes its root

When an external WebSocket language server sends workspace/applyEdit for an app-accessible URI outside context.rootUri, this handler opens and modifies that unrelated local, SAF, SFTP, or FTP document without checking workspace membership.

How this was verified: The request path reaches workspace.displayFile and the general-purpose file opener without a workspace-root check.

Knowledge Base Used:

Comment thread src/cm/lsp/transport.ts
Comment on lines +217 to +223
const plugin = LSPPlugin.get(view);
if (!plugin) {
failures.push(uri);
continue;
}

const applied = applyTextEdits(plugin, view, edits);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Workspace edit uses wrong client

When multiple LSP clients are attached to a document, unfiltered LSPPlugin.get(view) can select a plugin other than the requesting client's. applyTextEdits then maps positions through that client's syncedDoc and unsyncedChanges, causing replacements at incorrect offsets or rejecting a valid edit.

Knowledge Base Used: LSP Integration

Comment on lines +27 to +33
resolveUris(server, context: LspRuntimeUriResolutionContext) {
const documentUri = sftpUriToFileUri(context.originalDocumentUri);
const rootUri = context.originalRootUri
? sftpUriToFileUri(context.originalRootUri)
: null;
return { documentUri, rootUri, scope: "workspace" };
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 SFTP client identities collide

When two SFTP connections use the same language server and remote root path but different hosts, ports, or credentials, resolveUris strips their authorities before the workspace-scoped cache key is built. The second workspace therefore reuses the first connection's LSP client, associating diagnostics, navigation, completion, and edits with the wrong remote host.

Knowledge Base Used:

Comment on lines +9 to +15
function sftpUriToFileUri(uri: string): string | null {
const match = /^sftp:\/\/[^/]*(\/.*)$/.exec(uri);
if (!match) return null;
const path = match[1].split("?")[0];
if (!path) return null;
return "file://" + path;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 SFTP paths become malformed URIs

When an SFTP root or document path contains spaces, Unicode requiring escaping, #, or another URI-significant character, this raw concatenation overrides the encoded URI produced by buildFileUri. The server can then reject the URI, initialize against the wrong root, or treat part of the path as a fragment and fail to locate the document.

Knowledge Base Used:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

1 participant