Mercury CLI
Documentation

Code

Language servers

Mercury's LspRead tool and its refactor tools (LspRename, LspMoveSymbol, LspMoveFile, LspCodeAction and LspFormat) speak to the language servers of the workspace. LspRead answers symbol questions from the compiler's knowledge. The refactor tools write with that knowledge, and every write goes through the same permissions, journaled commit walk, file-history snapshot, change receipt and read-before-edit rule as the Edit tool.

On hosted models that support deferred tools, LspRead and the refactor tools load on demand through ToolSearch when a language server is configured. Discovery reads local configuration, installed binaries and bundled servers; a server starts when needed. MERCURY_LSP=0 and --lean keep the tool off. Local models keep their existing tool set. A deferred tool discovered after the first request is available at once; a tool that loads in full joins at the next compaction or /clear.

Diagnostics and failures

A diagnostics result says whether a server checked the files. After a Bash command writes a file, the next diagnostics read waits for the language server's fresh report; when no language server covers a file, Edit and Write report newly introduced syntax errors and missing syntax nodes in TypeScript, Python, Rust, Go and C files immediately after the write through the bundled tree-sitter grammars (alongside JSON, YAML and TOML syntax checks). When a server failed to start, did not answer or cannot claim the file, the result names the cause and what to fix. After three consecutive server faults for the same call in the same situation, Mercury pauses that call for 60 seconds, growing to at most five minutes; a changed named file or server state allows it again at once. Failed server starts have their own 15-second to five-minute backoff, cleared by an explicit restart or /extensions reload. A failed check leaves the project's own diagnostics unread.

From the composer, /lsp status prints the serverStatus rows, /lsp restart <server> stops and starts one server at once, and /lsp restart alone restarts the whole language service for the workspace and re-reads configuration so each server starts on the first file it claims. Restarting waits for any in-flight initialization, kills the full language-server process tree (including children behind Windows .cmd shims), refuses if survivor processes remain, and reports each server's stop outcome (exited cleanly, exited with code <N>, or killed after <N> s); an unknown server name is refused with the roster. From the command line, mercury lsp list prints every catalogue server with its installed binary path or its platform install remedy (using Windows tools such as winget, scoop, rustup and cs or vendor Windows builds on Windows). mercury lsp install <server> shows a server's install remedy, asks for confirmation (--yes for scripts), runs it and reports where the binary landed (on Windows, .cmd and .bat shims such as npm.cmd resolve through PATHEXT and run via cmd.exe /d /s /v:off /c). Mercury never installs a language server on its own.

Language services

  • TypeScript and JavaScript: The built-in mercury-ts sidecar drives the project's own typescript package (or Mercury's packaged compiler, which ships its standard library type definitions beside it so a project with no tsconfig.json and no typescript package of its own still resolves standard globals such as Math, Promise, Object and String methods without false errors).
  • Python, C/C++, GDScript and C#: Built-in language-service lanes serve these languages.
  • Catalogue servers: When a server's binary is on PATH (or in node_modules/.bin) and its workspace root marker matches, Mercury routes to rust-analyzer, gopls, zls, jdtls, kotlin-language-server, kotlin-lsp, csharp-ls / OmniSharp, sourcekit-lsp, ruby-lsp, intelephense, phpactor, lua-language-server, bash-language-server, yaml-language-server, marksman, terraform-ls, docker-langserver, elixir-ls, expert, helm_ls, vue-language-server, svelteserver, astro-ls, tailwindcss-language-server, PowerShell Editor Services (pwsh), haskell-language-server, ocamllsp, metals, nil, dart, gleam, prisma-language-server, clojure-lsp and julia.
  • Additional servers: An extension or MERCURY_LSP_SERVERS adds servers.
  • Read operations: Definitions, references, hover, symbols, call hierarchy and diagnostics. The first workspaceSymbol call starts the workspace's implied language server when none is running yet and excludes TypeScript standard-library symbols from workspace results.

The TypeScript sidecar finds the nearest tsconfig.json or jsconfig.json above a file. A jsconfig.json project is analyzed whole, so a rename in one JavaScript file reaches the others. A file under neither uses an implicit project rooted at the nearest package.json folder (bounded by the session's starting folder), while preserving CommonJS shorthand export keys across renames.

Refactor operations

  • LspRename (rename): Renames the symbol at filePath, line and character to newName at every location the service reports: the declaration, imports and re-exports, JSX tags and attributes, and JavaScript files in the same project. A comment or a string that contains the name is never a reference.
  • LspMoveSymbol (moveSymbol): Moves the top-level function, class, interface, type, enum or variable declaration named at filePath, line and character to targetPath, creating the file when it does not exist and appending when it does, with every import rewritten by the compiler. TypeScript and JavaScript only.
  • LspMoveFile (pathRename): Moves the file or directory at filePath to newPath with the import edits of every server that claims the file, as one transaction. A directory move claims through the extensions of the files it contains. If any participating language server fails its workspace/willRenameFiles request or returns malformed edits, LspMoveFile aborts before moving or editing any file and names the server.
  • LspCodeAction (codeActions): Lists the quick fixes, refactors and source actions the service provides at a position or range, each with a stable identifier beginning ca- derived from what the action is.
  • organizeImports: The code action of kind source.organizeImports (or LspFormat with organizeImports: true). It changes only the import block.
  • fixDiagnostic: Reads the diagnostics at a position, lists the fixes, applies the sole candidate and reports the error count before and after.

Preview a refactor

Call the refactor tool (LspRename, LspMoveSymbol, LspMoveFile, LspCodeAction or LspFormat) with its parameters, leaving apply unset. The tool returns each edit as data (the file, the one-based start and end line and character, the text before and the text after) in the edits field, along with a plan token beginning lsp- that digests the exact edit set over the exact file contents. Nothing is written.

Apply a previewed refactor

Repeat the operation with apply: true and the returned plan token. The tool recomputes the edits against the current files, writes the previewed set, and reports the post-apply diagnostics.

The apply refuses when any touched file changed since the dry run, because the token no longer matches. Without plan, the apply writes only files the session has read as they stand now: a full Read whose content matches, a windowed Read covering the touched lines, or lines shown by a content search. A touched file the session has not read refuses the whole apply, names the files and their lines, and points at the dry run. A refused apply writes nothing. After an apply, the read state of every written file is refreshed, the editor is notified and the servers are re-synced.

Rename checks

The TypeScript sidecar checks a rename with the compiler before the edits are offered. The new name must be a valid identifier that is not a reserved word. A rename that would introduce a compiler error, or would change which symbol a name refers to, is refused with the compiler's message and position. A rename the service itself refuses, such as a library symbol or an unresolved identifier, is refused with the service's reason.

A moveSymbol position must identify the declaration's name. Refused by name: a position inside a body, a statement that is not a declaration, a target that is the source, a directory, or a file of another language. The server of another language lane answers that it does not offer a symbol move.

Code-action selection

  • kind: Filters the list to quickfix, refactor or a sub-kind such as refactor.extract, or to the whole-file source actions source.organizeImports, source.addMissingImports, source.removeUnusedImports and source.removeUnused. Source actions are offered only when asked for by kind.
  • actionId: Without apply, previews that action's edits and plan.
  • apply: true: Writes the action named by actionId, or the one action left by kind when the kind leaves exactly one.

A command-only action, one that would run code on the server, is refused. A refactor that would create a file is refused in favor of moveSymbol.