Files
pi-lsp/README.md
Evan Reichard e131e0e8cd feat: add server control commands (disable, enable, destroy)
Add /lsp-servers, /lsp-disable, /lsp-enable, and /lsp-destroy TUI commands.
Disabled servers are tracked in-memory per-extension-instance; the shared
daemon is never mutated by disable/enable. When all servers are disabled,
LSP tools are removed from the active tool set so the LLM won't attempt them.

Also adds a destroy_server daemon operation that kills running LspClient
entries by server ID or all entries.
2026-04-30 09:48:01 -04:00

135 lines
3.9 KiB
Markdown

# evan/pi-lsp
LSP extension for pi coding agent. Provides LSP tools that the LLM can use to query language servers, plus automatic diagnostics after edit/write operations.
## Features
### LSP Tools (callable by LLM)
- `lsp_hover` - Get hover documentation for a symbol
- `lsp_definition` - Find the definition of a symbol
- `lsp_references` - Find all references to a symbol
- `lsp_completion` - Get completion suggestions
- `lsp_documentSymbol` - Get the symbol outline of a file
- `lsp_diagnostics` - Get lint/type-check diagnostics
### Auto-Check
Automatically runs LSP diagnostics after `edit` or `write` tool calls. If issues are found, sends a message with the diagnostics to the LLM.
**Enable/disable:**
```bash
pi --lsp-auto-check=false # Disable auto-check
pi --lsp-auto-check=true # Enable (default)
```
### Manual Check Command
Run diagnostics manually on specific files:
```bash
/lsp-check main.go utils.go
```
### Server Control Commands
Disable a server so this pi instance won't use it (the shared daemon and other instances are unaffected). When all servers are disabled, LSP tools are removed from the active tool set.
| Command | Args | Behavior |
|---------|------|----------|
| `/lsp-servers` | none | List running servers and disabled state |
| `/lsp-disable` | `[<id>]` | Disable all (no arg) or specific server. Bare command disables all. |
| `/lsp-enable` | `[<id>]` | Enable all (no arg) or specific server. Restores tools when any is enabled. |
| `/lsp-destroy` | `[<id>]` | Kill running daemon entries for all (no arg) or specific server. Explicitly destructive. |
```bash
/lsp-disable gopls # Disable just gopls; other LSP tools still work
/lsp-disable # Disable all — removes LSP tools from active set
/lsp-enable gopls # Re-enable gopls; restores tools
/lsp-enable # Re-enable all
/lsp-destroy gopls # Kill running gopls process(es) in the daemon
/lsp-destroy # Kill all running server processes
```
## Install
```bash
cd ~/.pi/extensions/lsp
npm install
```
## CLI Usage (for development/testing)
```
tsx ./cli.ts <file> <lsp_command> <req_data_json> [--no-daemon]
tsx ./cli.ts daemon <status|stop>
```
Requests use a long-lived background daemon by default. The daemon is
autospawned on first use, keeps one language server alive per
`(server.id, project root)`, and evicts idle servers after
`ServerConfig.idleTtlMs` (default: 5 minutes). Pass `--no-daemon` to use the
legacy one-shot path for debugging.
`req_data_json` is the raw LSP params for the command, minus
`textDocument.uri` (we inject that from `<file>`).
### Commands
- `hover`
- `definition`
- `references`
- `completion`
- `documentSymbol`
- `diagnostics` (waits briefly for the first `publishDiagnostics`)
### Examples
```bash
# Hover at line 224, col 23 (LSP is 0-indexed, so subtract 1)
npm run lsp -- backend/api/server.go hover \
'{"position":{"line":223,"character":22}}'
# Go to definition
npm run lsp -- backend/api/server.go definition \
'{"position":{"line":223,"character":22}}'
# Document symbols (no params needed)
npm run lsp -- backend/api/server.go documentSymbol '{}'
# Diagnostics
npm run lsp -- backend/api/server.go diagnostics '{}'
# Inspect/stop the background daemon
npm run lsp -- daemon status
npm run lsp -- daemon stop
```
Set `LSP_DEBUG=1` to forward server stderr to the daemon log. The daemon
socket is `$XDG_RUNTIME_DIR/pi-lsp-$UID.sock` (tmpdir fallback); logs are in
`/tmp/pi-lsp-daemon.log`.
## Adding A Server
Edit `server.ts`:
```ts
{
id: "rust-analyzer",
match: ["rs"],
command: "rust-analyzer",
args: [],
rootMarkers: ["Cargo.toml"],
languageId: "rust",
}
```
## Adding A Command
1. Add to the `LspCommand` union in `src/types.ts`.
2. Add a handler in `src/commands.ts`.
## Future
- **Daemon hardening** - persistent metrics, health checks, and richer status output.
- **Build output** - ship compiled JS entrypoints instead of relying on tsx for development.