Files
deepseek-harness/packages/lsp/lsp
Tianyi Cui d488330ba4 fix(rebase): migrate the replayed E2B branch onto the rebased parent
The linear replay carried old-lineage content over parent-owned files;
this checkpoint restores them and adapts the branch to the parent's
post-rebase seam:

- restore all pty/lsp/subprocess/code-runtime surfaces to the parent's
  exact content (this branch claims none of them) and drop the net-zero
  code-runtime-e2b/pty-e2b/lsp-e2b residue and its registrations
- widen serializeRemoteEnvironment to the seam's NodeJS.ProcessEnv
  tombstone contract: an explicit undefined removes an ambient entry
- migrate the two E2B fixture Agent stubs to the Inbox-model interface
  and Session.create
- re-apply the branch's gen-doc-graphs roles, THIRD_PARTY_NOTICES e2b
  row, and packages/README group row (trimmed to the doc budget);
  regenerate catalogs and re-record bilingual pairings
2026-08-08 22:19:13 +08:00
..

@deepseek-ai/dsh-lsp

English | 中文

The LSP capability seam: an abstract LspService (ctx.lsp) defining WHAT semantic code navigation the harness has — go to definition, find references, find implementations, hover — over language-server providers, without binding the model contract to local subprocesses.

This package is the interface third of the LSP capability:

Package Role
@deepseek-ai/dsh-lsp (this) the interface: the service, provider registry keyed by branded id + extension mapping, per-query selection, request/result vocabulary, the LspError taxonomy
@deepseek-ai/dsh-lsp-local a generic local backend that registers configured stdio language-server providers
@deepseek-ai/dsh-tool-lsp the model-facing lsp tool over ctx.lsp

The seam exposes exactly four semantic operations — goToDefinition, findReferences, goToImplementation, hover — and no generic JSON-RPC escape hatch, so no protocol payload or unreviewed command/mutation reaches a provider through ctx.lsp.

Service API (ctx.lsp)

Member Semantics
registerProvider(provider) Register a backend, atomically reserving its branded id and every normalized file extension. Any invalid input or conflict publishes nothing and throws LspError (LSP_INVALID_PROVIDER / LSP_CONFLICT). Returns a disposer releasing all reservations. Disposed with the calling fiber.
query(request, signal?) Select the provider by the file's final extension, derive the languageId from that provider's mapping, and run one query. No match throws LspError LSP_UNAVAILABLE.

Selection is per query and order-independent: a provider owns a set of extensions exclusively, so registration and HMR order never change routing. Extension keys normalize to lowercase, leading-dot form; the languageId only synchronizes the transient document, never participates in selection. The first version has no glob, language-id, or explicit route selector.

Providers register capabilities, not tools. dsh-tool-lsp is the only owner of the model-facing name, description, prompt guidance, schema, and presentation.

Vocabulary

LspQueryRequest (operation, filePath, position, workspaceRoot) — every field required, so no field needs implementation defaulting and there is no resolve() step. Positions and ranges are zero-based UTF-16, matching the protocol; the tool owns the one-based cursor convention. findReferences always includes declarations — providers enforce this internally, so callers get no flag. LspQueryResult is a CLOSED discriminated union: { kind: 'locations'; locations; resolvedWorkspaceUri } for navigation, { kind: 'hover'; hover } for hover (content or null) — consumers switch to exhaustiveness so a new arm breaks compilation until handled. resolvedWorkspaceUri is the provider's canonical workspace file: URI; callers relativize location URIs against it instead of applying host-platform path rules to the possibly symlinked request root. See src/types.ts for the full contracts and src/index.ts for the LspError codes, including LSP_DISPOSED and LSP_MALFORMED_RESPONSE.

Model Experience

Indirectly, through dsh-tool-lsp, which owns the model-facing lsp schema, prompt, and rendered results while this registry contributes no prompt or schema itself.

KV Cache effect

No direct invalidation; dsh-tool-lsp owns request-prefix changes.

Known Limitations and Deferred Work

  • Exclusive extension ownership within one runtime — two providers cannot both claim .ts, even with different language ids; overlaps fail registration. The intended extension is a deployment-configured selector above registrations, which can relax exclusive reservation without adding provider choice to model input (seam Agent Note).
  • Four operations only — symbols and call hierarchy are deferred (they need different schemas); diagnostics need separate freshness/accumulation rules; mutations (rename, code actions, formatting) require separate tools with preview, permission, and write-policy integration.
  • No observation surface — availability is observed only by running query() and routing the thrown LspError codes; there is no provider-change event or capability-status query.