Personal Knowledge Base

修哥筆記

「知識的沉澱與分享」

LSP 是什麼?Hermes Agent 如何用它與 Astro 語言伺服器

· #LSP #Hermes #Astro #TypeScript #開發工具 #教學

編輯器或 AI Agent 要「理解」程式碼,最可靠的方式不是用正規表示式硬掃,而是讓一個懂語言的程式來分析。Language Server Protocol(LSP) 正是這個「懂語言的程式」與各種前端之間的標準通訊協議。本文先介紹 LSP 的原理,再說明 Hermes Agent 內建的 LSP 診斷系統能帶來什麼好處,最後以本站 Astro 專案為例,記錄安裝與使用 astro-language-server 的完整流程與踩坑。

目標讀者:用 Hermes Agent 管理程式專案的人,以及想知道「Agent 如何做到寫完檔案立刻抓型別錯誤」的開發者。

一、LSP 是什麼?

LSP 是微軟在 2016 年提出的協議,核心概念是把「程式語言分析」抽離成一個獨立的語言伺服器(language server)程序,透過 JSON-RPC 與編輯器(或任何客戶端)溝通。

傳統做法是每個編輯器各自實作每種語言的功能——VSCode 要自己寫 Python 補全、Neovim 也要寫一份,重複又難維護。有了 LSP:

  • 語言伺服器只需實作一次:它用 initializetextDocument/didOpentextDocument/publishDiagnostics 等標準方法,提供自動補全、跳轉定義、型別檢查、診斷、hover 說明等功能。
  • 客戶端只需實作一次:VSCode、Neovim、Emacs 甚至 AI Agent,只要會講 LSP 協議,就能享用所有語言的完整能力。

實際運作流程大致是:

編輯器 / Agent  ──didOpen(檔案)──▶  語言伺服器
                ◀──publishDiagnostics(診斷)──
                ──didChange(修改)──▶
                ◀──publishDiagnostics(最新診斷)──

以 Astro 為例,官方維護的 @astrojs/language-server 會解析 .astro 檔案——frontmatter 的 TypeScript、template 的 JSX、以及兩者的互動——找出型別錯誤、未定義變數、屬性錯誤等,回報給客戶端。

二、Hermes Agent 的 LSP 系統:寫完檔案立刻檢查

Hermes Agent 內建一套 LSP 診斷系統(hermes lsp 指令),架構上等同於頂級 AI 編碼工具的實作:在每次 write_file / patch 寫入檔案後,自動呼叫語言伺服器,回報「這次編輯新引入的」問題。重點設計如下:

  1. Delta 過濾:寫入前先快照檔案目前的診斷作為基準,寫入後重新查詢,只呈現「新出現的」錯誤。舊有的問題不會被重複回報,也不會把前一次編輯的錯誤誤報成現在的。
  2. 雙通道檢查:先跑極快的語法檢查(毫秒級),語法乾淨後才呼叫 LSP 做語意診斷(型別錯誤、未定義名稱、缺 import)。LSP 掛掉絕不影響寫入——所有失敗路徑都靜默退回語法檢查結果。
  3. Git workspace 門檻:LSP 只在檔案位於 git 儲存庫內時啟動,避免在雜亂目錄(例如家目錄)無謂地啟動常駐程序。
  4. 延遲啟動與閒置回收:語言伺服器在第一次使用時才啟動(1–3 秒),閒置 600 秒後自動關閉,下次用到再喚醒。長時間運作的 gateway 不會累積一堆沒用的伺服器程序。
  5. 新鮮度門檻:診斷只在伺服器針對「目前內容」產生時才算數;慢伺服器來不及回報就回報「無資料」,絕不拿舊錯誤充數。

支援的語言超過 20 種:Python(pyright)、TypeScript、Vue、Svelte、Astro、Go、Rust、C/C++、Bash、YAML、PHP、Dockerfile、Terraform 等。

對 Agent 工作流的好處

  • 錯誤當場被抓:我修改 .astro.ts 檔案後,LSP 診斷會出現在寫入結果中,型別錯誤、未定義變數、壞掉的 import 立刻可見,不用等到 build 才爆炸。
  • 不中斷流程:診斷是附加資訊,伺服器壞掉或太慢都只是「少一層檢查」,不會卡住寫檔。
  • 多語言統一:一個系統涵蓋整個技術棧,不需要為每種語言裝不同外掛。

三、安裝 Astro LSP:完整步驟與踩坑

以下以本站專案(~/xiuge-notes,Astro v7)為例,從零開始安裝。

步驟 1:確認 Hermes LSP 服務狀態

hermes lsp status

可以看到 astro-language-servertypescript 都顯示 [missing](尚未安裝)。服務本身預設啟用。

步驟 2:安裝語言伺服器

hermes lsp install astro-language-server
hermes lsp install typescript

Hermes 會把套件裝進 ~/.hermes/lsp/(自己的暫存區,不動系統目錄),並在 ~/.hermes/lsp/bin/ 建立執行檔連結。

步驟 3:確認專案是 git 儲存庫

LSP 只在 git workspace 內啟動。若專案尚未版控:

cd ~/xiuge-notes
git init
# 建立 .gitignore 排除 node_modules/、dist/、.astro/ 等
git add -A && git commit -m "Initial commit"

步驟 4:踩坑——TypeScript 7 與 astro-ls 不相容

裝好後實際編輯 .astro 檔,第一次回報了這個錯誤:

lsp[astro-language-server] spawn/initialize failed:
LSP error -32603: Request initialize failed with message:
The `typescript.tsdk` init option is required.

設定 typescript.tsdk 後錯誤變成:

Can't find typescript.js or tsserverlibrary.js in
"/home/sugarwu/.hermes/lsp/node_modules/typescript/lib"

原因:Hermes 自動安裝的 TypeScript 是 7.x(以 Go 重寫的原生移植版),它的 lib/ 目錄沒有傳統的 typescript.js / tsserverlibrary.js,而 Volar 架構的 astro-language-server 需要傳統 TypeScript 5.x 的 API。

解法是把 Hermes 的 LSP 環境降版到 TypeScript 5.x,並把 tsdk 指向它:

cd ~/.hermes/lsp
npm install typescript@5          # 安裝 5.9.3,lib/typescript.js 存在

hermes config set lsp.servers.astro-language-server.initialization_options.typescript.tsdk \
  "/home/sugarwu/.hermes/lsp/node_modules/typescript/lib"

步驟 5:調高等待時間(冷啟動較慢)

astro-ls 內嵌 TypeScript 服務,冷啟動可能超過預設的 5 秒等待上限,導致「無資料」:

hermes config set lsp.wait_timeout 20.0

步驟 6:驗證

確認狀態顯示 installed

hermes lsp status
# ✓ typescript            [installed  ]
# ✓ astro-language-server [installed  ]

實際測試:故意在 .astro 檔引入錯誤,寫入後診斷立即出現:

ERROR [5:24] Type '"nonexistent-collection"' does not satisfy the constraint '"posts"'. (ts)
ERROR [9:22] Cannot find name 'thirdUndefinedVar'. (ts)
ERROR [9:6]  'testUndefined' is declared but its value is never read. (ts)

補充:整包型別檢查 astro check

LSP 是「編輯當下」的檢查;若要整包掃描,Astro 官方提供 astro check。本站已將依賴加入 package.json

npm install -D @astrojs/check typescript
npm run check
# Result (12 files): 0 errors, 0 warnings, 8 hints

小結

LSP 讓「語言理解」成為一個可重用的標準服務,Hermes Agent 把它接進寫檔流程,實現「寫完立刻檢查、只報新錯誤」的閉環。對 Astro 專案而言,安裝 astro-language-server 後,Agent 改動 .astro / .ts 檔案時的型別安全有了即時保障——唯一的坑是 TypeScript 7 的原生移植版與 Volar 不相容,降版到 5.x 並指定 tsdk 即可解決。

← 返回首頁