Skip to content

LSP-Tool für semantische Codesuche (nach vorherigem Spike) #32

Description

@webmatze

Priorität: 3 — das aufwendigste Einzelfeature der Roadmap und das mit dem unsichersten Nutzen-Verhältnis. Bewusst als letztes eingeordnet. Vor der Umsetzung sollte ein Spike klären, ob sich der Aufwand gegenüber grep tatsächlich auszahlt.

Referenz: Claude Code v2.0.74 (LSP-Tool für Go-to-Definition, Find-References, Hover), v2.1.0 (Tool wurde fälschlich aktiviert, wenn keine Server konfiguriert waren), v2.1.153 (Race Condition beim Start).

Motivation

smith findet Code heute ausschließlich über grep und glob. Das ist textuell und kennt keine Semantik:

  • „Wo wird Registry#execute_single_call aufgerufen?" → grep findet auch Kommentare, Strings und gleichnamige Methoden anderer Klassen
  • „Was ist der Typ hier?" → gar nicht beantwortbar
  • „Alle Implementierungen von Approver" → nur mit Glück über Namenskonventionen

Ein LSP-Client macht daraus präzise Anfragen und spart Kontext: Statt 200 Grep-Treffer zu lesen und zu filtern, kommen fünf exakte Referenzen zurück. Bei Crystal ist das besonders reizvoll, weil crystalline als Language Server existiert.

Realistische Einschätzung (bitte vor der Umsetzung lesen)

Dieses Feature hat ein schlechteres Aufwand/Nutzen-Verhältnis als jedes andere in dieser Roadmap:

  • LSP ist ein umfangreiches Protokoll mit Initialisierung, Dokument-Synchronisation, Positionskodierung (UTF-16!) und servereigenen Eigenheiten
  • Jede Sprache braucht einen eigenen Server, der installiert sein muss
  • Der Nutzen hängt stark von der Serverqualität ab; crystalline ist gut, aber nicht mit rust-analyzer oder gopls vergleichbar
  • Ein großer Teil des Nutzens lässt sich mit gutem grep plus einem präzisen Prompt erreichen

Empfehlung: Erst einen Spike mit einer Sprache (Crystal via crystalline) und einer Operation (find references) bauen, im Alltag messen, ob es tatsächlich Kontext spart — und erst danach entscheiden, ob ausgebaut wird. Das Ergebnis dieses Spikes gehört als Kommentar in dieses Issue.

Spezifikation (nach positivem Spike)

Konfiguration

[[lsp.servers]]
name       = "crystal"
command    = "crystalline"
args       = ["--stdio"]
extensions = [".cr"]

[[lsp.servers]]
name       = "typescript"
command    = "typescript-language-server"
args       = ["--stdio"]
extensions = [".ts", ".tsx"]

Ohne konfigurierte Server wird das Tool nicht registriert — genau der Bug, den Claude Code in v2.1.0 fixen musste. Kein Tool anbieten, das nichts kann.

Tool lsp

{ "type": "object",
  "properties": {
    "operation": { "enum": ["definition", "references", "hover", "symbols", "diagnostics"] },
    "path":      { "type": "string" },
    "symbol":    { "type": "string", "description": "Symbol name; alternative to line/character" },
    "line":      { "type": "integer" },
    "character": { "type": "integer" }
  },
  "required": ["operation", "path"] }

Wichtig für die Brauchbarkeit: Modelle denken in Symbolnamen, nicht in Zeilen/Spalten. Das Tool sollte symbol unterstützen und intern über documentSymbol die Position auflösen. Ein Tool, das exakte Koordinaten verlangt, wird vom Modell kaum korrekt bedient.

Rückgabeformat

Kompakt und für ein Modell lesbar, nicht rohes LSP-JSON:

References to Registry#execute_single_call (3):
  src/smith/tools/registry.cr:77   res = execute_single_call(call)
  src/smith/tools/registry.cr:129  res = execute_single_call(call)
  spec/tools/registry_spec.cr:44   registry.execute_single_call(...)

Fallstricke

  • Positionskodierung: LSP verwendet standardmäßig UTF-16-Codeunits für Spalten. Bei ASCII-Quelltext fällt das nie auf und bricht dann bei der ersten Datei mit Umlauten oder Emoji. Von Anfang an korrekt umrechnen.
  • Dokument-Synchronisation: Der Server muss den aktuellen Dateiinhalt kennen. Nach jedem write_file/edit_file ist ein didChange/didSave nötig, sonst arbeitet der Server auf veraltetem Stand und liefert falsche Positionen — was schlimmer ist als keine Antwort.
  • Start-Latenz: Große Projekte indizieren mehrere Sekunden bis Minuten. Server lazy beim ersten lsp-Call starten, nicht beim Sessionstart, und Anfragen bis zur Bereitschaft zurückstellen (CC v2.1.153).
  • Lebenszyklus: wie bei MCP — Shutdown inklusive Signal::INT-Handler, keine Waisenprozesse.

Umsetzung

src/smith/lsp/protocol.cr    # JSON-RPC über stdio, Content-Length-Framing (nicht zeilenbasiert wie MCP!)
src/smith/lsp/client.cr      # initialize, didOpen/didChange, Requests
src/smith/lsp/manager.cr     # Server pro Sprache, Lebenszyklus
src/smith/tools/lsp_tool.cr

Synergie: Wird das MCP-Issue zuerst umgesetzt, ist die JSON-RPC-Basis dort bereits vorhanden und sollte geteilt werden. Achtung auf den Unterschied im Framing: MCP über stdio nutzt zeilenbasiertes JSON, LSP nutzt Content-Length-Header. Die Request/Response-Zuordnung und der Lese-Fiber sind aber identisch.

Tests (spec/lsp/)

Gegen einen Fake-LSP-Server in Crystal, keine externe Toolchain in der Testsuite:

  • Content-Length-Framing beim Senden und Empfangen, auch bei Nachrichten über mehrere Reads
  • UTF-16-Positionsumrechnung für eine Zeile mit Umlauten und Emoji
  • symbol → Position über documentSymbol aufgelöst
  • Anfrage vor Server-Bereitschaft wird zurückgestellt, nicht verworfen
  • Server nicht installiert → klare Meldung, Session läuft weiter
  • Keine Server konfiguriert → Tool fehlt in registry.specs
  • Shutdown hinterlässt keine Prozesse

Akzeptanzkriterien

  • Spike-Ergebnis ist in diesem Issue dokumentiert und positiv
  • LSP-Tool nur bei konfigurierten Servern registriert
  • Symbolbasierte Anfragen funktionieren ohne manuelle Koordinaten
  • UTF-16-Positionen korrekt umgerechnet, mit Test
  • Dokument-Synchronisation nach Dateiänderungen
  • Keine Waisenprozesse
  • Ausgabe ist kompakt und modelltauglich
  • crystal spec grün, Format sauber, README-Abschnitt „LSP"

Nicht-Ziele

  • Rename/Refactoring über LSP (Schreiboperationen bleiben bei edit_file)
  • Code-Completion
  • Automatische Installation von Language Servern

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestneeds-infoWaiting on reporter for more informationprio:3Gross, strategisch, spaeterroadmapTeil der Claude-Code-Feature-Analyse

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions