Lsp refactor
Use for ANY rename, file-move, or move-symbol refactor — especially rename-heavy work across multiple files. Claude Code's built-in LSP tool is READ-ONLY (find references, but no rename / file-move / move-symbol). Hand-editing those refactors silently misses re-exports, aliased imports, type-only imports, and {@link} doc references. This skill drives a real language server via the `lspeasy` CLI to apply a correct WorkspaceEdit that catches every reference. Trigger when the user asks to rename a function/class/variable/type project-wide, move a file and fix its importers, or pull a symbol out into another module.From its SKILL.md
npx -y skills add pradeepmouli/lspeasy --skill lsp-refactorAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
5.0 KB, as published. Nobody here has run it
lsp-refactor
Drive write-side refactors through a real language server instead of hand-editing.
Why this exists
Claude Code's built-in LSP tool is read-only — definition, references, hover,
but no rename, no file-move, no code-action apply. So multi-file refactors otherwise fall
to manual edits, which miss the references a compiler would catch:
- re-exports (
export { foo } from './x') — and the public-alias formexport { newName as foo } - aliased imports (
import { foo as bar }) - type-only imports (
import type { Foo }) {@link foo}references in JSDoc
The lspeasy CLI sends a real textDocument/rename / workspace/willRenameFiles /
refactor.move to the language server and applies the returned WorkspaceEdit. The server
sees the whole program, so it updates all of the above. This is strictly more correct than
ripgrep-and-replace, and it is what you should reach for on rename-heavy work.
The CLI
Run it via npx (no install) or the lspeasy bin if @lspeasy/cli is installed:
npx @lspeasy/cli <command> ... # zero-install
lspeasy <command> ... # if installed (pnpm add -g @lspeasy/cli)
Commands (positions are 1-based, line:col, editor-style):
lspeasy rename <file> <line:col> <newName>
lspeasy move-file <oldPath> <newPath>
lspeasy move-symbol <file> <line:col> <targetFile>
lspeasy query <definition|references|hover> <file> <line:col>
Useful flags:
--root <dir>— project root (default: cwd). Point this at the package whosetsconfigowns the file.--dry-run— print the affected files / edit counts and change nothing. Always do this first.--json— machine-readable output on stdout (diagnostics go to stderr).--server <cmd>— LSP server launch command (defaulttypescript-language-server --stdio). Any server advertising rename / codeAction / willRenameFiles works.--wait <ms>— how long to let the server index before requesting (default 15000). Large repos may need more.
Workflow
Do one operation at a time and verify between each — that keeps any failure attributable to a single change.
-
Find the symbol position. Use the read-only
LSPtool (definition) or ripgrep to locate the declaration. You need the file and the 1-basedline:colof the identifier. -
Dry-run first. Run the command with
--dry-runto see which files would change and how many edits. Sanity-check the file list — if a re-export or test file you expected is missing, the position or--rootis probably wrong. -
Apply. Re-run without
--dry-run(apply is the default). The CLI applies the WorkspaceEdit and, formove-file, physically moves the file (git mvwhen tracked). -
Verify. Run the project's type-check / build, then review the actual changes with
git diff(andgit diff --statfor the file overview). For TypeScript:tsgo --noEmitortsc --noEmit(use whatever the repo uses). A clean compile plus a diff that touches only the expected files is your confirmation. -
Repeat for the next operation. Don't batch unrelated refactors into one step.
Examples
# Rename a function project-wide (declaration at src/math.ts line 1, col 17)
npx @lspeasy/cli rename src/math.ts 1:17 sumValues --root . --dry-run
npx @lspeasy/cli rename src/math.ts 1:17 sumValues --root .
# Move a file and update every importer, then git mv it
npx @lspeasy/cli move-file src/helpers.ts src/util/helpers.ts --root .
# Move a symbol into another module (updates importers automatically)
npx @lspeasy/cli move-symbol src/math.ts 5:17 src/helpers.ts --root .
Notes / honesty
- rename reliably updates re-exports, aliased/type-only imports, and
{@link}references. - move-symbol targets an existing file (the server moves the symbol and rewrites importers);
it relies on the language server's
refactor.movecode action. For TypeScript this istypescript-language-server; other servers must advertise the same capability. - After a
move-fileormove-symbol, eyeball the moved block's formatting — language servers re-indent moved code and that may differ from the repo's formatter. Run the formatter if needed. - If a command returns "no edit", the project likely hadn't finished indexing — re-run with a
larger
--wait, or confirm--rootpoints at the right tsconfig.