diff --git a/docs/lsp-config.md b/docs/lsp-config.md index e6fa0a3f3..61d82eaf1 100644 --- a/docs/lsp-config.md +++ b/docs/lsp-config.md @@ -211,6 +211,7 @@ The following servers ship in `defaults.json` and are eligible for auto-detectio | `hls` | Haskell | `haskell-language-server-wrapper` | | `ocamllsp` | OCaml | `ocamllsp` | | `elixirls` | Elixir | `elixir-ls` | +| `expert` | Elixir | `expert` | | `erlangls` | Erlang | `erlang_ls` | | `gleam` | Gleam | `gleam` | | `solargraph` | Ruby | `solargraph` | diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index c1b019efa..eac550966 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Added + +- Added the Expert Elixir language server (`expert`, invoked as `expert --stdio`) to the built-in LSP server list, auto-detected for Mix projects (`mix.exs`/`mix.lock`). When both are installed, `elixir-ls` remains the primary navigation server (Expert is ordered after it). + ## [15.11.0] - 2026-06-10 ### Breaking Changes diff --git a/packages/coding-agent/src/lsp/defaults.json b/packages/coding-agent/src/lsp/defaults.json index 23b752ccc..21ec89a63 100644 --- a/packages/coding-agent/src/lsp/defaults.json +++ b/packages/coding-agent/src/lsp/defaults.json @@ -248,6 +248,12 @@ } } }, + "expert": { + "command": "expert", + "args": ["--stdio"], + "fileTypes": [".ex", ".exs", ".heex", ".eex"], + "rootMarkers": ["mix.exs", "mix.lock"] + }, "erlangls": { "command": "erlang_ls", "args": [], diff --git a/packages/coding-agent/test/tools/lsp-regressions.test.ts b/packages/coding-agent/test/tools/lsp-regressions.test.ts index 4b323fdc3..efbfc2493 100644 --- a/packages/coding-agent/test/tools/lsp-regressions.test.ts +++ b/packages/coding-agent/test/tools/lsp-regressions.test.ts @@ -38,6 +38,7 @@ import type { ToolSession } from "@oh-my-pi/pi-coding-agent/tools"; import { clampTimeout } from "@oh-my-pi/pi-coding-agent/tools/tool-timeouts"; import * as piUtils from "@oh-my-pi/pi-utils"; import { sanitizeText, TempDir } from "@oh-my-pi/pi-utils"; +import DEFAULTS from "../../src/lsp/defaults.json" with { type: "json" }; describe("lsp regressions", () => { afterEach(() => { @@ -1829,3 +1830,13 @@ for await (const chunk of Bun.stdin.stream()) { expect(output).toContain("typescript-language-server (ready)"); }); }); + +describe("expert elixir lsp", () => { + it("registers expert for .ex while keeping elixirls primary", () => { + const config = { servers: DEFAULTS as unknown as Record }; + const names = getServersForFile(config, "lib/app.ex").map(([name]) => name); + expect(names).toContain("expert"); + expect(names).toContain("elixirls"); + expect(names.indexOf("elixirls")).toBeLessThan(names.indexOf("expert")); + }); +});