H繁中版
<!-- Source: https://hermesbible.com/docs/user-guide/features/lsp -->

Section: Core Features · URL: https://hermesbible.com/docs/user-guide/features/lsp

Language Server Protocol (LSP)

Hermes 會在背景子進程中執行完整的語言伺服器 — pyright、gopls、rust-analyzer、typescript-language-server、clangd 以及約 20 種其他語言 — 並將它們的語義診斷資訊整合到 write_filepatch 使用的寫入後 lint 檢查中。當 agent 編輯檔案時,它能看到該次編輯引入的所有錯誤 — 不僅是語法錯誤,還包括語言伺服器偵測到的型別錯誤、未定義的名稱、遺漏的 import,以及專案範圍的語義問題

這是頂級 coding agent 採用的相同架構。Hermes 以自包含方式提供:不需要編輯器主程式、不需要安裝外掛、不需要管理獨立的 daemon。

LSP 何時運行

LSP 的運行取決於 git 工作區偵測。當 agent 的工作目錄(或正在編輯的檔案)位於 git 儲存庫內時,LSP 會針對該工作區運行。當兩者都不在 git repo 中時,LSP 保持休眠 — 這在訊息閘道器中很有用,因為工作目錄通常是使用者的 home 目錄,沒有需要診斷的專案。

檢查機制是分層的:先進行進程內語法檢查(微秒級),語法通過後再進行 LSP 診斷。不穩定或缺失的語言伺服器永遠不會破壞寫入操作 — 每個 LSP 失敗路徑都會靜默回退到僅語法檢查的結果。

具體來說,每次 write_filepatch 成功執行時:

  1. Hermes 擷取檔案目前診斷的基線。
  2. 執行寫入。
  3. 重新查詢語言伺服器,過濾掉基線中已存在的診斷,只顯示新的診斷。

agent 看到的輸出類似:

{
  "bytes_written": 42,
  "dirs_created": false,
  "lint": {"status": "ok", "output": ""},
  "lsp_diagnostics": "LSP diagnostics introduced by this edit:\n<diagnostics file=\"/path/to/foo.py\">\nERROR [42:5] Cannot find name 'foo' [reportUndefinedVariable] (Pyright)\nERROR [50:1] Argument of type \"str\" is not assignable to \"int\" [reportArgumentType] (Pyright)\n</diagnostics>"
}

lint 欄位攜帶語法檢查結果(透過 ast.parsejson.loads 等進行微秒級進程內解析);lsp_diagnostics 欄位攜帶來自真實語言伺服器的語義診斷。兩個通道、兩個獨立的訊號 — 當檔案語法正確但有語義問題時,agent 會看到 lint: ok 加上有內容的 lsp_diagnostics

支援的語言

語言伺服器自動安裝
Pythonpyright-langservernpm
TypeScript / JavaScript / JSX / TSXtypescript-language-servernpm
Vue@vue/language-servernpm
Sveltesvelte-language-servernpm
Astro@astrojs/language-servernpm
Gogoplsgo install
Rustrust-analyzer手動安裝 (rustup)
C / C++clangd手動安裝 (LLVM)
Bash / Zshbash-language-servernpm
YAMLyaml-language-servernpm
Lualua-language-server手動安裝 (GitHub releases)
PHPintelephensenpm
OCamlocaml-lsp手動安裝 (opam)
Dockerfiledockerfile-language-server-nodejsnpm
Terraformterraform-ls手動安裝
Dartdart language-server手動安裝 (dart sdk)
Haskellhaskell-language-server手動安裝 (ghcup)
Juliajulia + LanguageServer.jl手動安裝
Clojureclojure-lsp手動安裝
Nixnixd手動安裝
Zigzls手動安裝
Gleamgleam lsp手動安裝 (gleam install)
Elixirelixir-ls手動安裝
Prismaprisma language-server手動安裝
Kotlinkotlin-language-server手動安裝
Javajdtls手動安裝

對於「手動安裝」的項目,請透過該語言對應的工具鏈管理器安裝伺服器(rustup、ghcup、opam、brew 等)。Hermes 會自動偵測 PATH 上或 <HERMES_HOME>/lsp/bin/ 中的執行檔。

有少數伺服器在安裝時需要伴隨的相依套件,而 npm 不會自動拉取。目前的情況是 typescript-language-server,它需要從同一個 node_modules 樹中匯入的 typescript SDK — 當你執行 hermes lsp install typescript 或觸發首次使用自動安裝時,Hermes 會同時安裝這兩個套件。

CLI

hermes lsp status          # 服務狀態 + 各伺服器安裝狀態
hermes lsp list            # 登錄表,可選 --installed-only
hermes lsp install <id>    # 主動安裝一個伺服器
hermes lsp install-all     # 嘗試安裝所有有已知設定的伺服器
hermes lsp restart         # 終止運行中的用戶端
hermes lsp which <id>      # 印出解析後的執行檔路徑

hermes lsp status 是最佳的起點 — 它會顯示哪些語言現在能獲得語義診斷,以及哪些需要安裝執行檔。

設定

預設值適用於一般設定;如果執行檔在 PATH 上,則無需設定。

# config.yaml
lsp:
  # 主開關。停用後會跳過整個子系統 — 不會產生伺服器,
  # 也不會執行背景事件迴圈。
  enabled: true

  # 每次寫入後等待診斷的時間。
  wait_mode: document      # "document" or "full"
  wait_timeout: 5.0

  # 如何處理缺失的伺服器執行檔。
  #   auto    — 透過 npm/pip/go install 安裝到 <HERMES_HOME>/lsp/bin
  #   manual  — 僅使用 PATH 上已有的執行檔
  install_strategy: auto

  # 各伺服器的覆寫設定(全部可選)。
  servers:
    pyright:
      disabled: false
      command: ["/abs/path/to/pyright-langserver", "--stdio"]
      env: { PYRIGHT_LOG_LEVEL: "info" }
      initialization_options:
        python:
          analysis:
            typeCheckingMode: "strict"
    typescript:
      disabled: true       # 即使副檔名符合也跳過 TS

各伺服器的設定項

  • disabled: true — 即使副檔名符合,也完全跳過此伺服器。
  • command: [bin, ...args] — 指定自訂執行檔路徑。會繞過自動安裝。
  • env: {KEY: value} — 傳遞給衍生進程的額外環境變數。
  • initialization_options: {...} — 合併到 initialize 握手時發送的 LSP initializationOptions 載荷中。屬於伺服器特定設定;請參閱該語言伺服器的文件。

安裝位置

install_strategy: auto 時,Hermes 會將執行檔安裝到 <HERMES_HOME>/lsp/bin/。NPM 套件會放在 <HERMES_HOME>/lsp/node_modules/,bin 符號連結位於上一層。Go 執行檔來自 go installGOBN 指向暫存目錄。

不會安裝到 /usr/local/~/.local/ 或任何其他共享位置 — 暫存目錄完全由 Hermes 管理,重設設定檔時會一併移除。

效能特性

LSP 伺服器採用延遲啟動模式,僅在首次使用時才啟動。在一個從未編輯過 .py 檔案的專案中編輯 Python 檔案時,才會啟動 pyright;多數伺服器的啟動時間為 1-3 秒(rust-analyzer 在冷專案上可能需要 10 秒以上)。同一工作區內的後續編輯會重用已運行的伺服器。

當沒有診斷輸出時,LSP 層僅增加數毫秒的延遲。當有診斷輸出時,等待預算為 wait_timeout 秒 — 通常 pyright/tsserver 會在數十毫秒內回應,rust-analyzer 在索引期間可能需要數秒。

伺服器會在 Hermes 進程的整個生命週期中保持運行。沒有閒置超時回收機制 — 因為在每次寫入時重新啟動伺服器索引的成本,遠高於保持 daemon 運行的成本。

停用

config.yaml 中設定 lsp.enabled: false 即可停用整個子系統。寫入後的檢查會回退到進程內語法檢查(Python 使用 ast.parse、JSON 使用 json.loads 等),這與先前版本的行為相同。

若要停用單一語言而不影響整個層級:

lsp:
  servers:
    rust-analyzer:
      disabled: true

疑難排解

hermes lsp status 顯示伺服器為 "missing"

執行檔不在 PATH 上,也不在 <HERMES_HOME>/lsp/bin/ 中。執行 hermes lsp install <server_id> 嘗試自動安裝,或透過該語言的一般工具鏈手動安裝執行檔。

hermes lsp status 中出現 Backend warnings 區段

有些伺服器是包裝外部 CLI 的輕量封裝 — 它們能正常啟動並接受請求,但當伴隨的執行檔缺失時不會發出錯誤。最常見的情況是 bash-language-server,它將診斷工作委派給 shellcheck。當 hermes lsp status 顯示 Backend warnings 區段時,請透過作業系統的套件管理器安裝指定的工具:

apt install shellcheck      # Debian / Ubuntu
brew install shellcheck     # macOS
scoop install shellcheck    # Windows

同樣的警告也會在伺服器啟動時記錄到 ~/.hermes/logs/agent.log 一次。

伺服器啟動但從未回傳診斷

檢查 ~/.hermes/logs/agent.log 中的 [agent.lsp.client] 條目 — 語言伺服器的 stderr 和協定錯誤都會記錄在那裡。有些伺服器(尤其是 rust-analyzer)需要完成專案範圍的索引後才會發出檔案診斷;伺服器啟動後的第一次編輯可能在沒有診斷的情況下完成,後續編輯才會取得診斷。

伺服器崩潰

崩潰的伺服器會被加入 broken-set,在該 session 餘下的時間內不會重試。執行 hermes lsp restart 即可清除該集合;下次編輯時會重新啟動。

編輯 git repo 外的檔案

根據設計,LSP 只在 git 儲存庫內運行。如果專案尚未初始化,請執行 git init 來啟用 LSP 診斷。否則會套用進程內僅語法檢查的回退機制。