dsh-plugin
DayuanJiang/next-ai-draw-iodsh 的 draw.io 绘图插件:通过 next-ai-drawio MCP 服务器作图,点回复里的链接在右侧栏打开实时预览,可以手动修改图,AI 的每次修改都是可以恢复的版本。需 Node.js 18+,首次使用由 npx 下载 MCP 服务器。
实时 LSP 诊断闭环:通过无头 stdio 语言服务器(TypeScript/JavaScript + Python)提供 lsp_diagnostics / lsp_workspace_errors / lsp_hover 工具,并订阅 harness 的 fs/observed 事件自动注入「本次编辑引入的诊断增量」——为 dsh Agent 带来 Cursor 式的编辑→诊断→修复体验。
English | 中文
Real-time compiler/LSP diagnostics — a DeepSeek Harness (dsh) plugin that closes the edit → diagnostics → fix loop: the model edits a file, immediately sees what broke (file:line:col + code + message), and fixes it. This is Cursor's killer feature, for dsh agents.
| Tool | Purpose |
|---|---|
lsp_diagnostics | Current diagnostics for one file (or all files the servers have seen), filtered by severity, capped. Call right after editing a file. |
lsp_workspace_errors | All errors across the workspace — the "what is broken right now" view. |
lsp_hover | Type/signature info at a position (optional helper). |
Plus an optional auto-injected system prompt section (lsp:diagnostics, order 70): after the model writes/edits a file through the harness, the plugin subscribes to the fs/observed event, refreshes the file on its language server, and injects only the new/changed diagnostics introduced by that edit — never the whole workspace. Stale deltas expire (sectionTtlMs, default 30s). Set autoInject: false to disable and rely on the tools only.
model edits file ──► dsh writes it (fs tool)
│
▼ fs/observed event
plugin refreshes the file on its LSP server
│
▼ publishDiagnostics
delta injected into the prompt (or lsp_diagnostics on demand)
│
▼
model reads "src/a.ts:12:3 error TS2322 …" ──► fixes it
Requires dsh (any install path — npx, npm, or source), Node ≥ 22, and the LSP servers on PATH:
npm i -g typescript-language-server typescript
npm i -g pyright
Both servers are npm-installable — no Python runtime, no native binaries.
# from npm (prebuilt)
npx @deepseek-ai/dsh plugin --profile web add dsh-lsp-diagnostics
# or from a directory containing this checkout
npx @deepseek-ai/dsh plugin --profile web add ./dsh-lsp-diagnostics
Restart the Web UI (npx @deepseek-ai/dsh web) — startup logs confirm each tool:
[dsh-lsp-diagnostics] plugin loaded
[dsh-lsp-diagnostics] registered tool: lsp_diagnostics
...
Missing a server? The tools say so, with the exact install command: LSP server "pyright-langserver" is not installed or failed to start. Install it with: npm i -g pyright.
In a workspace session, ask the agent:
src/extract.ts to split out the parser, then check it with lsp_diagnostics."lsp_workspace_errors)code at line 121?" (lsp_hover)Example (input → output):
lsp_diagnostics { file: "src/extract.ts" }
# diagnostics (3 errors, 1 warning)
src/extract.ts:121:10 error TS2304 Cannot find name 'foo'
src/extract.ts:144:3 error TS2322 Type 'string' is not assignable to 'number'
src/store.ts:8:5 warn TS6133 'x' is declared but never used
The canonical JSON (severity, range, code, message, source) is what execute returns; the compact table above is the rendered view.
Options are passed as the plugin row's config in the profile patch (or defaults are used if absent):
# $DSH_HOME/profiles/<name>/cordis.patch.yml — a bare row overrides by id.
- id: lsp-diagnostics
config:
maxDiagnostics: 30
autoInject: true
| Key | Default | Meaning |
|---|---|---|
autoInject | true | Register the auto-injected diagnostics section (and the fs/observed listener) |
maxDiagnostics | 50 | Hard cap on diagnostics surfaced by tools and the injected section (token-cost guard) |
languages | ['typescript','javascript','python'] | Which servers to boot; TS and JS share one server |
serverPath | {} | Per-server binary override ({typescript: …, python: …}); a path ending in .js/.mjs/.cjs runs under the current Node |
sectionTtlMs | 30000 | How long an injected delta stays current (min 1000) |
typescript-language-server (.ts .tsx .mts .cts .js .jsx .mjs .cjs)pyright-langserver (.py .pyi)Rust (rust-analyzer is a native binary) is deliberately deferred — servers.ts is the seam where further servers plug in (command, args, install hint).
src/lspClient.ts): one headless JSON-RPC client over stdio per server process, built on vscode-languageserver-protocol + vscode-jsonrpc only (no VS Code bits). initialize/initialized handshake → full-text didOpen/didChange sync → publishDiagnostics subscription → clean shutdown/exit/kill teardown.src/manager.ts): one server per (workspace root, language), spawned lazily on first use. A crashed server is restarted once (its open documents are replayed); a second crash marks the language degraded with a clear message instead of a respawn loop. Plugin unload kills every spawned server (verified by a lifecycle test).src/section.ts): subscribes to the harness fs/observed event (fired by @deepseek-ai/dsh-tool-fs after read/write/edit commit). The listener only queues the file (sync, never throws); a debounced refresh diffs the fresh diagnostics against the previous state per file and renders the delta..git (bounded), same as dsh-code-index. Files outside a repo are refused.maxDiagnostics; the injected view is a per-edit delta, not the workspace.lsp_workspace_errors covers files the servers have seen this session (a file joins the set the first time lsp_diagnostics checks it) — standard LSP open-file semantics, not a whole-repo batch scan.lib/tsserver.js; keep typescript@5 resolvable in the workspace (typescript-language-server falls back to its own bundled 5.x when the workspace doesn't pin one).PATH (or overridden via serverPath); no servers are bundled, by design.pnpm install
pnpm test # vitest — client handshake/mapping/tools/lifecycle against a fake LSP server
pnpm typecheck
pnpm build # tsup → dist/index.js (ESM, external deps)
The suite runs against tests/helpers/fakeLspServer.mjs — a minimal stdio LSP server that derives diagnostics from // diag: <severity> <code> <message> markers — so no real pyright/tsserver is needed in CI.
Found a bug, or a server/language you want next? Please open an issue.
MIT. Not affiliated with DeepSeek; built on the public dsh plugin surface.