fix(install): unwrap lspServers envelope in plugin .lsp.json (closes #1683)#1686
Open
sergio-sisternes-epam wants to merge 2 commits into
Open
Conversation
When a plugin ships a .lsp.json using the { "lspServers": { ... } }
wrapper format, _read_lsp_json() now detects and unwraps the envelope
instead of treating "lspServers" as a server name.
This fixes the silent skip with:
Skipping invalid LSP server 'lspServers': requires 'command'
The flat format (server names as top-level keys) continues to work
unchanged.
Fixes #1683
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes apm install handling of plugin-provided .lsp.json files by supporting the common { "lspServers": { ... } } wrapper format, so wrapped LSP server definitions are correctly discovered and converted into dependencies instead of being misinterpreted and skipped.
Changes:
- Update
_read_lsp_json()to unwrap the"lspServers"envelope when present. - Expand unit tests to cover wrapped
.lsp.jsonparsing, auto-discovery behavior, and end-to-end conversion into valid LSP dependencies.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/apm_cli/deps/plugin_parser.py |
Adds unwrap logic for the "lspServers" envelope and updates the docstring to document both supported formats. |
tests/unit/deps/test_plugin_parser_lsp.py |
Adds new tests covering wrapped parsing, auto-discovery with wrapper, and end-to-end dependency generation. |
Only unwrap the envelope when all values in the inner dict are dicts (i.e. it looks like a server map). A flat-format server literally named 'lspServers' would have scalar values like 'command', so the all-dicts check avoids mis-detecting it as an envelope. Adds a regression test for this ambiguous edge case. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TL;DR
Plugin
.lsp.jsonfiles using the{ "lspServers": { ... } }wrapper format are now correctly unwrapped during install, instead of being silently skipped with a misleading validation error.Problem
When a plugin ships a
.lsp.jsonusing the standard wrapper format:{ "lspServers": { "my-lsp-server": { "command": "my-lsp", "args": ["--stdio"], "extensionToLanguage": { ".ext": "mylang" } } } }_read_lsp_json()returned the parsed JSON verbatim, causing"lspServers"to be treated as a server name. Its nested dict value (containing the actual servers) was then treated as that server's config -- which lacks acommandfield, producing:The real LSP servers were never written to
.github/lsp.json.Fix
In
_read_lsp_json()(src/apm_cli/deps/plugin_parser.py), after parsing the JSON dict, detect whether it contains a"lspServers"key with a dict value. If so, return the inner dict (the actual server map). The flat format (server names as top-level keys) continues to work unchanged.This mirrors the envelope handling already used by
LSPIntegrator._write_target_config()when writing to Copilot and Claude config files.Changes
src/apm_cli/deps/plugin_parser.pytests/unit/deps/test_plugin_parser_lsp.pyTests added
test_unwraps_lsp_servers_envelope-- wrapped format returns inner serverstest_flat_format_still_works-- flat format regression guardtest_auto_discovery_with_lsp_servers_wrapper-- auto-discovered.lsp.jsonwith wrappertest_wrapped_lsp_json_produces_valid_deps-- end-to-end: wrapped file -> valid depsValidation
tests/unit/deps/test_plugin_parser_lsp.pyruff check+ruff format --checkcleanpylint R0801(duplication) cleanFixes #1683