feat(lsp): LSP capability seam, generic stdio provider, and lsp tool

Implements the LSP capability seam RFC as three packages: dsh-lsp (the
ctx.lsp interface — provider registry by branded id + exclusive extension
mapping, per-query order-independent selection, closed request/result
vocabulary, LspError taxonomy), dsh-lsp-local (a generic stdio language-server
provider — Content-Length JSON-RPC framing, per-(provider, workspace) process
single-flight, transient didOpen/query/didClose, an abortable per-instance
queue, UTF-16 negotiation, host-namespace source reads outside ctx.fs, and
bounded shutdown/kill teardown), and dsh-tool-lsp (the model-facing lsp tool —
four operations, one-based UTF-16 cursor conversion, workspace-grouped location
rendering, hover capping, a required session workspace, and a timeout budget).

Why: an agent had text search and file reads but no way to identify a program
symbol — follow an alias, connect an interface to implementations, or read an
inferred type — before changing code. Splitting model contract, seam, and local
subprocess behavior keeps the four semantic queries stable across future remote
or sandbox-native providers without leaking a JSON-RPC escape hatch.
This commit is contained in:
Dudu-0223
2026-07-16 12:05:35 +08:00
parent 66b2cfc609
commit d0029d8d60
56 changed files with 4527 additions and 30 deletions

147
pnpm-lock.yaml generated
View File

@@ -724,6 +724,80 @@ importers:
specifier: ^4.0.0-rc.7
version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
packages/lsp/lsp:
devDependencies:
'@deepseek-ai/dsh-brand':
specifier: workspace:^
version: link:../../util/brand
'@deepseek-ai/dsh-llm':
specifier: workspace:^
version: link:../../llm/llm
cordis:
specifier: ^4.0.0-rc.7
version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
packages/lsp/lsp-local:
dependencies:
schemastery:
specifier: ^3.18.0
version: 3.18.0
devDependencies:
'@deepseek-ai/dsh-brand':
specifier: workspace:^
version: link:../../util/brand
'@deepseek-ai/dsh-llm':
specifier: workspace:^
version: link:../../llm/llm
'@deepseek-ai/dsh-lsp':
specifier: workspace:^
version: link:../lsp
'@deepseek-ai/dsh-timeout':
specifier: workspace:^
version: link:../../util/timeout
cordis:
specifier: ^4.0.0-rc.7
version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
typescript:
specifier: ^6.0.3
version: 6.0.3
typescript-language-server:
specifier: ^5.0.0
version: 5.3.0
packages/lsp/tool-lsp:
dependencies:
schemastery:
specifier: ^3.18.0
version: 3.18.0
devDependencies:
'@deepseek-ai/dsh-agent':
specifier: workspace:^
version: link:../../core/agent
'@deepseek-ai/dsh-llm':
specifier: workspace:^
version: link:../../llm/llm
'@deepseek-ai/dsh-lsp':
specifier: workspace:^
version: link:../lsp
'@deepseek-ai/dsh-lsp-local':
specifier: workspace:^
version: link:../lsp-local
'@deepseek-ai/dsh-session':
specifier: workspace:^
version: link:../../core/session
'@deepseek-ai/dsh-system-prompt':
specifier: workspace:^
version: link:../../core/system-prompt
'@deepseek-ai/dsh-timeout-policy':
specifier: workspace:^
version: link:../../timeout/timeout-policy
'@deepseek-ai/dsh-tools':
specifier: workspace:^
version: link:../../core/tools
cordis:
specifier: ^4.0.0-rc.7
version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
packages/mcp/mcp-client:
dependencies:
'@modelcontextprotocol/sdk':
@@ -1171,7 +1245,7 @@ importers:
devDependencies:
cordis:
specifier: ^4.0.0-rc.6
version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
version: 4.0.0-rc.6(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
packages/support/subagent-mock:
dependencies:
@@ -3612,6 +3686,18 @@ packages:
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
engines: {node: '>= 0.6'}
cordis@4.0.0-rc.6:
resolution: {integrity: sha512-GzUv7zCKh3FlgM3/Ad2S03UpYO3v4u1GcKa7ig4K2je4lCrgJ/S64ziiZI6XNyKEa1tZwdzj4oBQrhYDLgfEiA==}
hasBin: true
peerDependencies:
'@cordisjs/plugin-include': ^1.0.4
'@cordisjs/plugin-loader': ^1.0.0-rc.4
peerDependenciesMeta:
'@cordisjs/plugin-include':
optional: true
'@cordisjs/plugin-loader':
optional: true
cordis@4.0.0-rc.7:
resolution: {integrity: sha512-5nm6ehrSfJhEUV659CctEvyNuBY/AXapw8+ZEw7YENztdzpiT+Ha8nIfkyhfyAgPtJns9aB5On5nzl9Sm6zHeQ==}
hasBin: true
@@ -5330,6 +5416,11 @@ packages:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: '>=4.8.4 <6.1.0'
typescript-language-server@5.3.0:
resolution: {integrity: sha512-5puofxZHgFdAYtfNpmwCAvgtaYgg8wrUnH30m7Ze3QuguId5RNRadKASpOpyDxTyUdAF51FjhTdjntLw/EuWcQ==}
engines: {node: '>=20'}
hasBin: true
typescript@6.0.3:
resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==}
engines: {node: '>=14.17'}
@@ -5471,6 +5562,20 @@ packages:
jsdom:
optional: true
vscode-jsonrpc@5.0.1:
resolution: {integrity: sha512-JvONPptw3GAQGXlVV2utDcHx0BiY34FupW/kI6mZ5x06ER5DdPG/tXWMVHjTNULF5uKPOUUD0SaXg5QaubJL0A==}
engines: {node: '>=8.0.0 || >=10.0.0'}
vscode-jsonrpc@9.0.1:
resolution: {integrity: sha512-rfuA6T75H6m5EkbhtEPzre9pT0HPcDI2MMy4+nPFIBks5J8JBAUHD4tRYSgaBOijIEC7SRkC1kKyXTLqbmh9jw==}
engines: {node: '>=14.0.0'}
vscode-languageserver-protocol@3.18.2:
resolution: {integrity: sha512-XRyDbT0Pp3sSNti3JmxVEUMySWCSi1hhM+/KUlCy1hV1zmrqpM1OwO12EAki8blhmLuIMpaJrYbo0OzGVfK2Qg==}
vscode-languageserver-types@3.18.0:
resolution: {integrity: sha512-8TsGPNMIMiiBdkORgRSvLjuiEIiAFtO+KssmYWxQ+uSVvlf7RjK8YKCOjPzZ+YA04jXEV7+7LvkSmHkhpNS99g==}
w3c-xmlserializer@5.0.0:
resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
engines: {node: '>=18'}
@@ -5876,6 +5981,14 @@ snapshots:
'@chevrotain/types@11.1.2': {}
'@cordisjs/plugin-include@1.0.4(@cordisjs/plugin-loader@1.0.0-rc.5)(cordis@4.0.0-rc.6)':
dependencies:
'@cordisjs/plugin-loader': 1.0.0-rc.5(cordis@4.0.0-rc.6)(node-addon-require-builtin@0.1.0)
cordis: 4.0.0-rc.6(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
cosmokit: 1.8.1
js-yaml: 4.2.0
optional: true
'@cordisjs/plugin-include@1.0.4(@cordisjs/plugin-loader@1.0.0-rc.5)(cordis@4.0.0-rc.7)':
dependencies:
'@cordisjs/plugin-loader': 1.0.0-rc.5(cordis@4.0.0-rc.7)(node-addon-require-builtin@0.1.0)
@@ -5891,6 +6004,14 @@ snapshots:
js-yaml: 4.2.0
optional: true
'@cordisjs/plugin-loader@1.0.0-rc.5(cordis@4.0.0-rc.6)(node-addon-require-builtin@0.1.0)':
dependencies:
cordis: 4.0.0-rc.6(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
cosmokit: 1.8.1
optionalDependencies:
node-addon-require-builtin: 0.1.0
optional: true
'@cordisjs/plugin-loader@1.0.0-rc.5(cordis@4.0.0-rc.7)(node-addon-require-builtin@0.1.0)':
dependencies:
cordis: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
@@ -7037,6 +7158,14 @@ snapshots:
cookie@0.7.2: {}
cordis@4.0.0-rc.6(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5):
dependencies:
'@standard-schema/spec': 1.1.0
cosmokit: 1.8.1
optionalDependencies:
'@cordisjs/plugin-include': 1.0.4(@cordisjs/plugin-loader@1.0.0-rc.5)(cordis@4.0.0-rc.6)
'@cordisjs/plugin-loader': 1.0.0-rc.5(cordis@4.0.0-rc.6)(node-addon-require-builtin@0.1.0)
cordis@4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5):
dependencies:
'@standard-schema/spec': 1.1.0
@@ -9038,6 +9167,11 @@ snapshots:
transitivePeerDependencies:
- supports-color
typescript-language-server@5.3.0:
dependencies:
vscode-jsonrpc: 5.0.1
vscode-languageserver-protocol: 3.18.2
typescript@6.0.3: {}
unbash@3.0.0: {}
@@ -9182,6 +9316,17 @@ snapshots:
transitivePeerDependencies:
- msw
vscode-jsonrpc@5.0.1: {}
vscode-jsonrpc@9.0.1: {}
vscode-languageserver-protocol@3.18.2:
dependencies:
vscode-jsonrpc: 9.0.1
vscode-languageserver-types: 3.18.0
vscode-languageserver-types@3.18.0: {}
w3c-xmlserializer@5.0.0:
dependencies:
xml-name-validator: 5.0.0