feat(config): add per-repo .pi-lsp.json server overrides
Users can now drop a .pi-lsp.json at any ancestor of their working files to add new LSP servers, override built-in ones, or disable servers entirely. The nearest config (walking upward) wins. - New src/config.ts: walks upward for .pi-lsp.json, parses, and merges with the built-in registry. Cached per config-file path with mtime invalidation. Falls back to built-ins on parse error. - Merge rules: matching id shallow-merges (user wins); new id appends (must include match/command/args/rootMarkers); `disable` filters at the end. - src/root.ts: pickServer() now resolves servers via the per-repo registry. Adds findServerById(filePath, id) and re-exports getServersForPath() for callers. - src/daemon.ts: getOrCreateEntry() resolves serverId against the filePath's config so spawned servers reflect repo overrides. - index.ts and cli.ts: replace direct `servers` imports with path-aware getServersForPath() lookups. - Tests: 9 new unit tests covering merge semantics, walk-up discovery, mtime invalidation, and graceful fallback. - Docs: README "Per-Repo Config" section + AGENTS.md updates.
This commit is contained in:
28
AGENTS.md
28
AGENTS.md
@@ -55,22 +55,42 @@ A per-entry `serializer` promise chain prevents concurrent syncs from racing.
|
||||
|
||||
```
|
||||
index.ts — Extension entry point (tools, commands, auto-check flag)
|
||||
server.ts — LSP server registry (gopls, typescript-language-server, pyright)
|
||||
server.ts — Built-in LSP server registry (gopls, typescript-language-server, pyright, ...)
|
||||
cli.ts — CLI for testing/debugging (daemon-aware or --no-daemon)
|
||||
daemon.ts — Entrypoint that starts the daemon process
|
||||
|
||||
src/
|
||||
client.ts — LspClient: spawns a language server, JSON-RPC handshake, file sync
|
||||
commands.ts — CLI command dispatcher (maps command names → LSP methods)
|
||||
config.ts — Per-repo `.pi-lsp.json` loader: walk-up + merge with built-ins, mtime cache
|
||||
daemonClient.ts — High-level helpers (daemonRequest, daemonDiagnostics, etc.)
|
||||
daemonProtocol.ts — Shared types, socket path, NDJSON send/receive, autospawn logic
|
||||
root.ts — pickServer(), findRoot(), URI/path conversion
|
||||
root.ts — pickServer(), findServerById(), getServersForPath(), findRoot(), URI/path conversion
|
||||
types.ts — ServerConfig interface, LspCommand union
|
||||
```
|
||||
|
||||
## Adding a Server
|
||||
### Per-Repo Config (`.pi-lsp.json`)
|
||||
|
||||
Edit `server.ts`. Add an entry to the `servers` array:
|
||||
Users can add/override/disable servers without editing `server.ts`. `src/config.ts`
|
||||
walks upward from a given path to find `.pi-lsp.json`, parses it, and merges
|
||||
with the built-in `servers` list:
|
||||
|
||||
- New `id` → appended (must supply `match`, `command`, `args`, `rootMarkers`).
|
||||
- Existing `id` → shallow-merged over the built-in (user fields win).
|
||||
- `disable: []` → filtered out at the end.
|
||||
|
||||
Results are cached per config path, invalidated by mtime. `getServersForPath(p)`
|
||||
is the **single entry point** — don't import the raw `servers` array from
|
||||
`server.ts` outside `src/config.ts`. The daemon resolves servers at
|
||||
`getOrCreateEntry()` time via `findServerById(filePath, id)`, so spawned
|
||||
servers reflect the config of the file being acted on. **Already-running**
|
||||
entries don't see config changes; users must `/lsp-destroy` to respawn.
|
||||
|
||||
## Adding a Server (Built-In)
|
||||
|
||||
For servers shipped with pi-lsp, edit `server.ts`. (For per-repo additions,
|
||||
users should drop a `.pi-lsp.json` at the repo root — see README.) Add an entry
|
||||
to the `servers` array:
|
||||
|
||||
```typescript
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user