feat: add LSP client library with JSON-RPC stdio + server registry #28

Merged
FO
4mo ago
+1028-28

Summary

Foundation for Wave S6 (IDE Integration) — shared LSP client and registry that all 3 tools (hover, references, diagnostics) will use.

Files Added

  • src/lib/lsp-client.ts — Core LSP Client

    • JSON-RPC 2.0 over stdin/stdout with Content-Length framing
    • Request/response matching via numeric IDs
    • Lifecycle: spawn → initialize → initialized → openDocument → shutdown
    • API methods: hover, references, diagnostics, documentSymbol
    • Timeout handling (30s init, 10s requests), graceful degradation
    • Logging via logDebugEvent()
    • Diagnotics cache populated by publishDiagnostics notifications
  • src/lib/lsp-registry.ts — Language Server Registry

    • Maps file extensions to LSP server commands
    • Pre-configured for: TypeScript/JS, Go, Python, Rust, PHP
    • resolveServer(filePath) — auto-selects server by file extension
    • isInstalled(command) — checks binary availability via which
    • shutdownAll() — cleanup
    • Singleton via getLspRegistry()
  • tests/lsp-client.test.ts — 39 tests (all passing)

    • JSON-RPC framing & Content-Length parsing (mock LSP server)
    • Request/response matching (concurrent requests)
    • Hover, references, documentSymbol, diagnostics
    • Timeout handling with graceful degradation
    • Shutdown lifecycle
    • Registry: file extension resolution for all 5 languages
    • Registry: null for unknown extensions, no-extension files
    • Registry: case-insensitive matching
    • Registry: isInstalled (system binaries + nonexistent)
    • Registry: register(), getConfigs(), singleton, shutdownAll

Test Results

39 pass, 0 fail, 79 expect() calls

Full suite: 213 pass, 0 fail across 19 files.

Also Modified

  • eslint.config.js — added Bun global declarations (clearTimeout, TextDecoder, TextEncoder, Timer, Uint8Array)

Closes #28


Summary by cubic

Adds a shared LSP client and server registry using JSON‑RPC over stdio and ships lsp_hover and lsp_references tools for Wave S6 IDE, addressing #28. Stabilizes the client lifecycle, makes initialization non‑blocking with rootUri, improves framing, and ensures safer shutdown and respawn.

  • New Features

    • lsp_hover: on‑demand docs; converts 1‑based positions; cleans/truncates markdown; includes fullContents; returns ToolResult JSON; registered in four-opencode-supertools.ts.
    • lsp-client: Content‑Length framed JSON‑RPC; non‑blocking auto‑initialize on spawn() with rootUri; idempotent initialize(); request timeouts; diagnostics cache; deduped openDocument(); openDocuments is now public.
    • lsp-registry: resolves by extension; checks install; respawns dead clients; derives rootUri from the file’s parent directory; returns null if spawn fails; getOpenDocuments() reads from public openDocuments.
  • Bug Fixes

    • Header parsing now tolerates extra headers and finds CRLFCRLF; lifecycle is cleared when streams close; in‑flight requests are rejected on shutdown.
    • Fixed init guard recursion; passed rootUri through spawn() to _startInit() to avoid empty roots and improve handshake reliability.
    • Tools return ToolResult‑compatible JSON strings; tests parse .output; improved isolation and timeouts.
    • Fixed stdio type casts; removed incomplete lsp_diagnostics; updated ESLint globals (TextEncoder, Uint8Array).

Summary by CodeRabbit

  • New Features

    • Added JSON-RPC 2.0 LSP client support for hover, references, document symbols, and diagnostics using framed stdio messaging with safe timeouts.
    • Added new LSP tools for hover and symbol references from a file path and cursor position (including formatted/trimmed output).
    • Extended the LSP registry to resolve servers by file extension, include PHP/Intelephense configuration, and surface currently open documents.
  • Tests

    • Added Bun test coverage for the LSP client, registry, hover tool, and references tool (mock LSP servers, timeouts, framing, truncation, shutdown).
  • Chores

    • Updated ESLint globals for additional runtime/browser-like identifiers.