DSH 的 LSP 动作面:诊断、格式化、补全、代码动作、符号、签名提示、inlay 提示与重命名,全部由真实语言服务器驱动。
安装
# npm 包(预构建)
dsh plugin --profile web add dsh-lsp-actions
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:PerryLink/dsh-lsp-actions
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本。请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
🛰️ dsh-lsp-actions
DeepSeek Harness 的 LSP 动作面 —— 真实的语言服务器,真实的反馈。
为你的 agent 编辑循环提供诊断、格式化、补全、快速修复、符号、签名提示与内联提示,驱动它们的正是你 IDE 所用的那些语言服务器。
English · 简体中文 · Español · हिन्दी · Português
这个插件给 agent 带来什么
官方 DeepSeek Harness 的 ctx.lsp seam 只覆盖导航(跳转定义、引用、实现、悬停)。dsh-lsp-actions 补齐了动作面 —— agent 写代码和修代码时需要的反馈闭环:
| 工具 | 做什么 | 写盘? |
|---|---|---|
lsp_diagnostics <file> |
编译器/分析器的错误、警告与提示(含严重级、范围、消息与来源服务器) | ❌ 只读 |
lsp_format <file> [range?] |
通过语言服务器格式化文件或选区并写入,返回 diff | ✅ 走 fs/write-intent + 沙箱策略 |
lsp_completion <file> <line> <character> |
光标处的补全建议,含实际插入文本 | ❌ 只读 |
lsp_code_action <file> [range?] [only?] |
服务器验证过的快速修复/重构(含其编辑) | ❌ 仅参考 |
lsp_symbols <query?> <file_path?> |
按名字全局搜索符号,或列出单个文件的符号大纲 | ❌ 只读 |
lsp_signature <file> <line> <character> |
调用点处的签名提示(参数与文档) | ❌ 只读 |
lsp_inlay_hints <file> [range?] |
服务器的类型标注与参数名提示 | ❌ 只读 |
lsp_rename <file> <line> <character> <new_name> |
服务器验证过的符号重命名,跨工作区应用并返回逐文件 diff | ✅ 走 fs/write-intent + 沙箱策略 |
✨ 测试套件包含一次真实的
typescript-language-server运行:诊断、格式化、补全、符号搜索与重命名都是对着活服务器端到端验证的,而非只有 mock。套件自包含(tsls 是 devDependency),并在 CI 中以 Node 22/24 × Linux/Windows/macOS 矩阵运行。
快速开始
dsh plugin --profile <name> add dsh-lsp-actions
卸载:
dsh plugin --profile <name> remove dsh-lsp-actions
每个语言服务器配一条 entry(形态与官方 lsp-stdio 配置一致):
# 写在 profile 的 cordis.patch.yml(或 bundle 行)里
- insert:
- id: lsp-actions
name: dsh-lsp-actions
inject: [tools, fs, subprocess]
config:
servers:
ts:
command: typescript-language-server
args: [--stdio]
extensionToLanguage:
".ts": typescript
formattingOptions: { tabSize: 2, insertSpaces: true }
py:
command: pyright-langserver
args: [--stdio]
extensionToLanguage:
".py": python
maxDiagnostics: 200
maxCompletionItems: 20
maxCodeActions: 50
maxSymbols: 100
maxSignatures: 10
maxInlayHints: 200
maxResultChars: 16000
timeoutMs: 60000
八个工具始终注册。当 servers 表为空且没有挂载 ctx.lsp seam 时,调用会响亮失败(LSP_ACTION_UNAVAILABLE,错误信息指明该配置什么)—— 插件绝不会启动你没有配置的服务器。在插件之后挂载的 ctx.lsp seam 会在下一次调用时被识别(seam 探测按调用惰性解析,加载顺序无关)。
为什么按构造就安全
- 格式化与重命名是真实写入,按
write/edit同等对待。 每个字节都经过fs/write-intentwaterfall(观测 → 守卫写 → 观测)与每次调用的沙箱策略。lsp_rename会在第一笔写入之前对每个待改文件做预检(工作区包含性、重叠检查、字节上限读取),坏服务器响应不可能留下写了一半的重命名。 - 其余一切按设计只读。 代码动作、补全、符号、签名与提示都作为参考材料返回;应用它们由模型自行决定用 write/edit 完成。命令形态只报告、绝不执行。
- 只读会话响亮、快速、结构化地失败 —— 在任何服务器往返之前抛出带共享
[sandbox: …]标记的LSP_ACTION_READ_ONLY。 - 升级路径与官方工具一致。 在受限文件系统下,
lsp_format与lsp_rename广告与write/edit相同的sandbox_permissions/justification一次性重试,经ctx.approval裁决。 - 冲突绝不覆盖。 若文件在读后被改动,守卫写以
LSP_ACTION_CONFLICT失败,并让模型二选一:重读后重跑,或手工应用 diff。 - 超时是平台职责。 每个工具声明
timeoutMs,由官方dsh-tool-call-timeout-policy执行,所有 await 尊重exec.signal。 - 不缓存任何东西。 结果只存在于会话日志,无跨会话持久化。
- 坏服务器响亮失败。 命令缺失在加载期即失败;启动即死的服务器以
LSP_ACTION_SERVER_FAILED+ stderr 尾部失败(启动失败先自动换新进程重试一次)。
架构
动作优先走官方 seam,未命中则回落插件自带的最小 stdio 客户端:
lsp_diagnostics / lsp_format / lsp_completion / lsp_code_action /
lsp_symbols / lsp_signature / lsp_inlay_hints / lsp_rename
│
▼
ctx.lsp seam(扩展后:diagnostics / formatDocument / completion)
│ 缺席 · 旧版 · 该文件无 provider
▼
内置 stdio 客户端 ← servers 表(ctx.subprocess.spawn + JSON-RPC)
seam 扩展已向上游提案(upstream/lsp-action-seam.patch,PR 描述见 upstream/PR-description.md)。合入后插件无需改动即自动迁移 —— 内置客户端停止被使用即可。内置客户端会保留为 servers 表的独立兜底。完整调研与设计笔记:docs/seam-extension-notes.md、upstream/README.md。
配置参考
interface Config {
/** 命名的语言服务器;为空 = 插件自带客户端不服务任何文件。 */
servers?: Record<string, LspServerEntry>
maxDiagnostics?: number // 默认 200
maxCompletionItems?: number // 默认 20
maxCodeActions?: number // 默认 50
maxSymbols?: number // 默认 100
maxSignatures?: number // 默认 10
maxInlayHints?: number // 默认 200
maxResultChars?: number // 默认 16000(完整渲染结果上限)
maxDocumentBytes?: number // 默认 4000000
timeoutMs?: number // 默认 60000(由官方超时策略执行)
}
interface LspServerEntry {
command: string // 可执行文件,加载期在 PATH 上解析
extensionToLanguage: Record<string, string> // ".ts" → "typescript"
fileGlobs?: string[] // 可选;glob 命中优先于扩展名映射
args?: string[] // 不经 shell
env?: Record<string, string>
initializationOptions?: unknown
configuration?: unknown // 对象形态按 section 应答 workspace/configuration
formattingOptions?: unknown // 例如 { tabSize: 2, insertSpaces: true }
maxMessageBytes?: number // 默认 16000000
maxStderrBytes?: number // 默认 1000000
killGraceMs?: number // 默认 2000
shutdownTimeoutMs?: number // 默认 5000
diagnosticsSettleMs?: number // 默认 2000(仅推送诊断的收集窗口)
diagnosticsDebounceMs?: number // 默认 250(最后一批推送后的安静期)
idleTimeoutMs?: number // 默认 0(0 = 服务器进程常驻)
}
错误码
每个失败都在错误结果上携带稳定 code;模型与调用方按 code 路由,绝不解析消息文本。
| Code | 含义 |
|---|---|
LSP_ACTION_UNAVAILABLE |
没有服务器 entry、seam provider 也不处理该文件。 |
LSP_ACTION_UNSUPPORTED |
服务器(或 seam provider)未广告该操作。 |
LSP_ACTION_SERVER_FAILED |
服务器失败(附 stderr 尾部);启动失败重试一次。 |
LSP_ACTION_MALFORMED_RESPONSE |
服务器返回了结构非法的负载。 |
LSP_ACTION_CONFLICT |
文件读后已变,或服务器返回的编辑重叠/越界/越出工作区。 |
LSP_ACTION_READ_ONLY |
会话沙箱模式禁止格式化/重命名写入。 |
LSP_ACTION_WORKSPACE_REQUIRED |
调用会话没有可扎根的 workspace cwd。 |
LSP_ACTION_NO_SYMBOL |
服务器在光标位置找不到可重命名的符号。 |
宿主版本支持
插件把 DeepSeek Harness 各包声明为 peerDependencies(@deepseek-ai/dsh-fs、dsh-llm、dsh-sandbox、dsh-subprocess、dsh-tools ≥ 0.1.0-rc.6),宿主与插件共享同一份副本。已在 0.1.0-rc.6 上实测,最后验证日期 2026-08-15。
已知限制
- 瞬态文档。 每次动作都是打开文件 → 发一个请求 → 关闭文件(与官方 stdio host 一致)。依赖常驻打开文件的基于项目的服务器(tsls 在无打开文档时拒绝
workspace/symbol)可通过给lsp_symbols传file_path解决 —— 插件会在该请求期间保持路由文件打开。tsls 在该生命周期下对textDocument/signatureHelp返回null;其他服务器(gopls、pyright、rust-analyzer)正常应答。 - 范围格式化要求服务器广告 range provider。 只广告全文格式化的服务器对范围请求以
LSP_ACTION_UNSUPPORTED失败。 - 重命名只应用文本编辑。 服务器重命名结果中的资源操作(新建/删除/重命名文件)以
LSP_ACTION_UNSUPPORTED拒绝;越出工作区的编辑在任何写入发生前以LSP_ACTION_CONFLICT失败。在utf-8/utf-32服务器上,跨文件重命名位置通过逐个读取被编辑文件来解码;被编辑文件不可读时以冲突失败,绝不错误解码位置。
开发
pnpm install
pnpm run lint # oxlint 检查 src/ 与 tests/
pnpm test # 240+ 测试:单元 + fixture 服务器集成 + 真实 tsls e2e
pnpm run test:coverage # 门禁:行/语句/函数 ≥ 90%,分支 ≥ 85%
pnpm build # 产出 lib/
发布
CI 在每次推送与 PR 上运行 lint/构建/测试矩阵 + 覆盖率门禁。推送 v* tag 会触发发布工作流:先验证全套测试再发布到 npm —— 需要在仓库里一次性配置 NPM_TOKEN Actions secret(发布权限的 npm access token)。版本号在打 tag 前于 package.json / CHANGELOG.md 中手动提升。
License
链接
同类插件
liustack/modlens★ 1582
为纯文本模型架起视觉桥梁:粘贴图片,输出结构化 JSON 证据(OCR、版面、语义)。
superdesigndev/treg★ 412
给 Agent 的工具目录:按「要做的事」检索约 2,600 个外部接口(SEO 与 SERP、外链、社交、人物与公司信息补全、广告库、抓取),查看参数与单次调用价格后直接调用,凭据由服务端注入。附带技能,MCP 行在未设置 TREG_TOKEN 前保持禁用。
Anionex/dsh-vision-toolkit★ 395
让纯文本模型更好地做视觉任务:带意图的图片问答、长截图 OCR、UI 还原等。
zhaoolee/notes★ 141
将 DSH 对话导出为锤子便签风格 PNG,或在配置的账号工作区中新建和更新 Markdown 便签。
Lum1104/dsh-browser★ 129
Chrome 侧边栏扩展,让 DSH 直接操控你的浏览器,无需视觉能力。
liustack/modsearch★ 101
纯文本 agent 的联网搜索桥:搜索网页与 X,返回结构化 JSON 证据(search/fetch/引用)。