LSP Auditor

πŸ“„ README β€” @cheasee-pi/lsp-auditor on npm

Why. Runs real Language Server Protocol diagnostics on changed files before code review β€” catches errors, warnings, and hints the LLM might miss. Called automatically by the supervisor pipeline during the Audit stage.

How it works. Triggered manually via /lsp-auditor or automatically by supervisor (runPreAudit()). Uses git diff <defaultBranch> --name-only to find changed files. Groups by file extension (.ts β†’ typescript-language-server, .py β†’ pylsp, .rs β†’ rust-analyzer, .go β†’ gopls). Spawns LSP servers per group, opens files via didOpen, collects publishDiagnostics notifications. Filters by per-server severityThreshold (error/warning/info). Retries up to 3 times with session-stored retry counters. Trust-gated β€” untrusted projects skip LSP audit (returns { proceed: true } with warning, matching VS Code Restricted Mode precedent).

Location: .pi/extensions/lsp-auditor/

Details

Architecture

Multi-server LSP orchestrator with file discovery and retry logic:

β”œβ”€β”€ index.ts              # Entry: command registration (/lsp-auditor), runPreAudit export
β”œβ”€β”€ run-pre-audit.ts      # Orchestrator: discover files β†’ group by server β†’ audit each group
β”œβ”€β”€ lsp-client.ts         # LSP client: spawn server, didOpen, collect publishDiagnostics
β”œβ”€β”€ server-mappings.ts    # Extension β†’ server mapping (.tsβ†’typescript-language-server, .pyβ†’pylsp, etc.)
β”œβ”€β”€ file-discovery.ts     # git diff file discovery + extension grouping
β”œβ”€β”€ formatting.ts         # Diagnostic formatting, severity filtering, result merging
β”œβ”€β”€ settings.ts           # Read .pi/settings.json for defaultBranch
β”œβ”€β”€ retry.ts              # Retry logic: countRetryAttempts, shouldRetry, MAX_RETRIES=3
β”œβ”€β”€ output-adapter.ts     # Mode-adaptive output formatting (TUI/RPC/JSON/print)
β”œβ”€β”€ types.ts              # LspDiagnostic, ServerMapping, AuditResult interfaces
└── test/                 # Unit + integration tests

Execution Flow

flowchart TD
    A[Trigger: /lsp-auditor or supervisor runPreAudit] --> B[file-discovery.ts: git diff defaultBranch]
    B --> C[groupFilesByServer: extension β†’ LSP server]
    C --> D{For each server group}
    D --> E[lsp-client.ts: spawn LSP server]
    E --> F[didOpen each file]
    F --> G[collect publishDiagnostics]
    G --> H[Filter by severityThreshold]
    H --> I[mergeResults across servers]
    I --> J{retry.shouldRetry?}
    J -- yes < 3 retries --> D
    J -- no --> K[formatting.ts: format output]
    K --> L[Return AuditResult: proceed / note]

Server Mappings

Extension LSP Server Notes
.ts typescript-language-server Full TS/TSX support
.py pylsp Python LSP
.rs rust-analyzer Rust LSP
.go gopls Go LSP
(others) β€” Skipped with warning

Key Design Decisions

  • File discovery via git diff β€” Only checks modified files vs defaultBranch. Prevents checking entire codebase. git diff <defaultBranch> --name-only.
  • Per-server severity threshold β€” Each server mapping configures severityThreshold (error/warning/info). Diagnostics below threshold are filtered out.
  • Retry with session-stored counters β€” Retries up to 3 times per server group. Counter stored in session scope. shouldRetry() checks both attempt count and error type (transient vs permanent).
  • Trust gate β€” Untrusted projects skip LSP audit entirely (returns { proceed: true } with warning). Matches VS Code Restricted Mode precedent.
  • Mode-adaptive output β€” TUI: notification + clickable markdown. RPC/JSON: structured { proceed, note, diagnostics }. Print: plain text.
  • Passive by default β€” No lifecycle hooks. Activated by supervisor’s runPreAudit() or manual /lsp-auditor command. All public API re-exported for supervisor imports.
  • Spawn + didOpen protocol β€” LSP servers are spawned on-demand, files opened via didOpen, diagnostics collected from publishDiagnostics notifications. No file watching needed.

Retry Logic

MAX_RETRIES = 3

function shouldRetry(attempts: number, error: Error): boolean {
  if (attempts >= MAX_RETRIES) return false;
  // Only retry on transient errors (connection refused, timeout, process crash)
  // Not on permanent errors (invalid file, missing server binary)
  return error.message.includes('ECONNREFUSED') ||
         error.message.includes('ETIMEDOUT') ||
         error.message.includes('process exited');
}

Testing

Tests cover:

  • File discovery: git diff parsing, empty diffs, binary file exclusion
  • Server mappings: extension matching, unknown extension fallback
  • LSP client: spawn, didOpen, diagnostic collection, timeout handling
  • Retry logic: attempt counting, transient vs permanent error classification
  • Formatting: severity filtering, result merging, markdown generation
  • Output adapter: all 4 modes (TUI, RPC, JSON, print)

Copyright © 2026 SchneiderDaniel. Distributed under the MIT License.

This site uses Just the Docs, a documentation theme for Jekyll.