OpenCode 2.2 開放桌面外掛:先看懂視窗與主程序怎麼分工

OpenCode 於 10 月 27 日發布 2.2.0,把桌面外掛以實驗功能開放:外掛程式碼第一次能進桌面版,而它能碰到什麼資源由跑在視窗或主程序決定。視窗與主程序各管一側、主程序獨持載入憑證,安裝仍是 npm 套件加一行設定,同版還有三項破壞性變更要逐項核對。

用 AI 摘要這篇文章:

OpenCode 在 10 月 27 日發布 2.2.0,changelog 裡的第一條亮點,就是把「建立、安裝與分享桌面外掛」以實驗功能之姿開放。這代表外掛程式碼第一次可以走進 OpenCode 的桌面版(OpenCode Desktop),在上面加面板、加指令、插設定頁。不過這次更新真正值得先讀懂的,是官方對「外掛程式碼在哪裡執行」畫出的那條線:一段程式碼能碰到什麼資源,由它跑在視窗還是主程序決定。這條線同時劃出能力上限與風險範圍,比任何面板示範都重要。

OpenCode 官方 changelog 截圖,v2.2.0 版本條目標示日期 October 27, 2026,Highlights 第一條為 Create, install and share Desktop plugins (experimental),附 PR 編號 55246、59469、59489Pin
v2.2.0 的第一條亮點:建立、安裝與分享桌面外掛,標註實驗功能。(來源:OpenCode)

也要先講清楚它沒有做什麼:OpenCode 沒有趁這次開一個外掛商店。發布形態仍然是 npm 套件,安裝仍然是在設定檔加一行,管理入口是設定頁裡的一個開關。對已經在伺服器端或終端機寫外掛的人,2.2 給的是第三個落點,而不是一套新的發布體系。

外掛第一次能進桌面版

OpenCode 的外掛系統原本有兩個落點:伺服器部分(server part)在 OpenCode server 裡跑,可以加工具、掛事件、加指令與代理;終端機部分(TUI part)在終端機介面裡跑,管介面層的事。2.2.0 補上第三個:GUI 部分,用 @opencode/plugin/gui 這組 SDK 撰寫,能把面板、指令、設定頁與原生整合加進桌面版。

具體形態是一個 npm 套件裡的一個出口。套件的 package.json 會長這樣:

{
  "name": "opencode-acme-plugin",
  "type": "module",
  "exports": {
    ".": "./src/index.ts",
    "./tui": "./src/tui.tsx",
    "./gui-experimental": "./dist/gui-experimental.cjs"
  }
}

三個部分可以並存在同一個套件裡,也可以只出 GUI 部分。GUI 部分自己不宣告 id,它沿用外掛的 id:有伺服器部分就用伺服器部分的,沒有就用套件名稱。官方文件寫得直白:使用者的安裝方式和一般外掛完全一樣,沒有另外的 GUI 安裝步驟。管理入口則在設定頁的 Extensions › Plugins,每個外掛掛著一個能把 GUI 關掉的開關。

有一個容易誤會的地方先澄清:桌面版應用本身不是這次才出現的東西,2.1.x 的版本紀錄裡已經有一串桌面版的改進條目,終端機版的許多功能它早就有了。2.2 打開的是它的擴充面,把「官方做什麼你就用什麼」變成「你和你的團隊可以自己加」。

出口名稱裡的 experimental 不是隨手加的綴詞。官方明說 GUI 外掛 API 是實驗性質,版本之間可能變動,這個名稱本身就是提醒。npm 上 @opencode/plugin 的版號也跟著主程式走:截至 10 月 31 日,最新版是 2.2.5,而 2.2.0 是 10 月 27 日發的,四天下了六個版本。實驗 API 加上這個節奏,維護成本該怎麼估,值得先想清楚。

時間點可以對得更精確。對應的合併紀錄集中在台北時間 10 月 27 日上午:PR #55246 在 8 時 54 分合併,標題就是「加入 OpenCode 桌面版 GUI 外掛」;同一個上午再接著合併 SDK 的介面 API(#59469)與設定頁的管理介面(#59489)。同版還有其他亮點,包括實驗性的圖片與決策生成 API、讓外掛用索引式條目維護 session 指示(改動不會打爆提示詞快取,也撐得過壓縮與還原),以及桌面版介面整體翻新。對要決定是否投入桌面外掛的讀者,這些是次要消息,真正影響決定的是接下來的結構問題。

一個檔案、兩個程序:放錯地方的程式碼只會拿到空殼

GUI 外掛最核心的設計,官方用一句話就講完了:一個檔案、兩個程序。整個 ./gui-experimental 檔案會被桌面版的兩種程序各自評估一次,讀的都是同一個預設匯出,但拿到的工作不一樣。

setup 在每個桌面視窗裡執行,貢獻看得到摸得到的東西:面板、指令、設定頁、插槽、伺服器來源、連結處理與樣式。main 只在 Electron 主程序執行一次,處理需要系統層資源的事:型別化的 IPC 通道、原生選單項目、嵌入式網頁檢視,以及 Node 與 Electron 的整合。想讓外掛直接動 Node、Electron 或檔案系統,那段程式碼只能放 main。

OpenCode 官方 GUI 外掛文件截圖,段落標題 One file, two processes,說明文字指出每個程序都會評估整個 gui-experimental 檔案,視窗執行 setup、主程序執行 main,下方附 src/gui.tsx 範例程式碼,setup 放視窗程式碼、main 放 electron 與 Node 整合Pin
官方文件的兩程序模型:同一個檔案,視窗跑 setup、主程序跑 main。(來源:OpenCode)

麻煩也藏在這裡。因為兩邊讀同一個檔案,官方用「惰性佔位」處理不屬於自己的模組:在視窗裡,electron 與 Node 內建模組是空殼;在主程序裡,Solid 與視窗專屬模組是空殼。官方文件的原話值得記住:跑錯程序的程式碼,拿到的是佔位物件,不是能用的值。這種錯誤不會在載入時炸開,模組照樣讀得進來,問題會晚一步、在你真的用到那個值的時候才浮現。把每段程式碼留在屬於它的 setup 或 main 裡,是官方給的第一條紀律。

官方文件自己的範例就把這條線示範得很清楚。一個「別讓螢幕睡著」的外掛:powerSaveBlocker(Electron 的電源管理 API)放在 main,視窗裡只放開關與狀態顯示,兩邊用 Ipc.define 定義的型別化通道連起來,視窗端透過 ctx.main 呼叫,主程序端用 ctx.provide 實作。這個切法幾乎可以直接當範本:會碰系統資源的往下放,給人看的往上放。

視窗端碰不到 Node 與 Electron,但能用的東西也不算少。文件列出的宿主 API 涵蓋版面操作(開關面板)、session 與對話畫面、把元件掛到輸入框附近、讀寫提示詞內容、切換模型、對話框、快訊提示、系統通知、分頁管理、快捷鍵,以及叫出系統檔案選擇器的 desktop.pick。換句話說,一般「在介面上顯示資訊、引導使用者操作」的需求,視窗端自己就做得完;真的需要讀檔案、開系統對話框、動視窗系統,才往 main 走。主程序端的整合點則是原生選單(macOS 的應用選單只在 macOS 出現)、嵌入式網頁檢視,加上完整的 Node 與 Electron 存取。

失敗怎麼傳遞也有明確規則。外掛的伺服器部分載入失敗,GUI 就不會出現;視窗裡依賴其他外掛提供的功能時,狀態有載入中、活躍、關閉、失敗四種,官方要求按狀態呈現,別讓按鈕變死鍵或讓載入圖示轉到天荒地老。至於自己的 main 沒有這套狀態機:透過 ctx.main 的呼叫會等它啟動,啟動不了就直接拒絕。

官方也把外掛之間的銜接設計了進來。一個外掛可以用 Registry.define 宣告自己擁有的清單(例如各種匯出方式),讓別的外掛用 ctx.add 貢獻項目;也能用 ctx.use 跟隨別人提供的功能,拿到的是帶狀態的存取器,上面提到的四種狀態就是為這種情境準備的。想在自家的幾個內部外掛之間拆分職責,不用把所有東西塞進同一個套件。

信任邊界:主程序拿著只有它有的鑰匙

把視角換到安全,文件「GUI 從哪裡載入」一節透露了整個設計的取向。

桌面版載入 GUI 的位置,就是原本就會載入外掛的那個背景伺服器,官方特別強調這不會新增一個程式碼來源。外掛清單仍然是設定檔裡的那一份,桌面版沒有多出一條獨立的安裝管道。接著是更關鍵的一句:主程序從自己的伺服器讀取外掛 bundle,用的是只有主程序持有的憑證,讀完再把同一組清單發給所有視窗,而視窗不能供給主程序程式碼。

id 也有保留字規則:撞到應用程式自己的外掛 id、用 . 巢狀掛在保留 id 底下、或佔用 opencode 命名空間,GUI 直接不載入,設定頁會把它列為未載入。命名時避開這些地雷,才不會裝了卻找不到原因。

在我讀來,這組規則把視窗當成低信任環境、把主程序當成高信任環境:視窗裡的程式碼碰不到 Node 與 Electron,也無法把自己升級成主程序程式碼;需要系統資源的行為集中在持有憑證的主程序,而且由外掛作者在定義裡明確宣告。對要在公司內部分發外掛的團隊,這代表風險範圍是可審的:看一段程式碼放在哪個程序,就知道它最多能碰到什麼。

打包與安裝:一個檔案和兩個坑

打包規則很硬:./gui-experimental 必須打包成單一個預先建置的 CommonJS 檔案。官方提供 @opencode/plugin/gui/vite 的 Vite preset,它負責用 vite-plugin-solid 編譯 JSX、輸出單一 CommonJS 檔案並把所有動態 import 收進同一個檔案,原因是應用程式無法載入第二個 chunk;同時把應用程式共用的模組與 Node 內建模組保持為外部依賴。想在 bundle 裡多塞一份 effect 或 solid-js,建置會直接失敗,因為應用程式不提供它,塞進去的副本也不會和應用程式共用同一個實例。

開發迴圈倒是順:vite build --watch 之後,每次重建會在所有視窗與主程序重載 GUI,伺服器部分不重啟。要注意的是版本語意:本機目錄跟著每次重建變動,但已安裝的套件,GUI 只會隨它的版本號變化,跑 opencode plugin update 才會換上新版。想在團隊裡鎖住版本,設定檔的 plugins 陣列支援 [email protected] 這種寫法,和鎖依賴套件是同一個思路。

安裝有兩個容易踩的坑。清單檔的坑先講:TUI 讀 cli.json,桌面版只讀 opencode.json(c)。一個原本只出 TUI 部分、使用者列在 cli.json 的套件,加了 GUI 之後必須補列進 opencode.json(c),否則桌面版看不到它。本機目錄則有另一條規則:沒有 package.json 的 name 與 exports 的本機目錄,只認根目錄下的 gui-experimental.cjs 或 .js,其他副檔名直接忽略。

移除的路徑也有交代:把外掛從設定檔拿掉,或跑 opencode plugin remove <package>。裝了以後使用者保留關掉的能力,這對內部分發的推廣是好事,同事試用後不喜歡,隨時能自己關掉。

對團隊還有個附帶好處:外掛清單活在設定檔裡,就能進版控。像 Adyen 開源的 Agent Marketplace 那種把代理工具設定同步到多種工具的作法,就能把 OpenCode 的桌面外掛清單一起納管,八種工具一份設定。

升級 2.2 之前要核對的破壞性變更

同一版 changelog 還列了三項破壞性變更,舊整合要跟著調:

變更影響對象官方指示
@opencode/ai 根出口改為 Promise API直接引用這個套件的整合Effect API 改從 @opencode/ai/effect 匯入;@opencode/ai/promise 移除;萬用子路徑出口換成明確清單
OpenCode GitHub Action 停止發布workflow 裡用了這個 Action 的專案從流程移除
TUI 外掛需要 OpenTUI 0.7依賴 OpenTUI 的終端機外掛依賴 0.6 的外掛安裝會直接失敯;升級後 hook 要在 constructor 指定,defineNativeIntegration() 換成靜態宣告

其中 GitHub Action 的移除在 10 月 25 日就合併了,比 2.2.0 的發布還早兩天,用行動時別被版本日期誤導。第一項的改動用官方給的 diff 最好看懂:

-import { AI } from "@opencode/ai/promise"
-import { LLM } from "@opencode/ai"
+import { AI } from "@opencode/ai"
+import { LLM } from "@opencode/ai/effect"

也要提醒:桌面 GUI 的新能力不會自動替既有的伺服器或終端機外掛處理相容性,升級前得逐項核對自己有用到的部分,而不是把三項當成一句「外掛都不能用了」。

現在該投入多少

把前面的線索合起來:API 標實驗、SDK 版號綁主程式、四天六個版本。就我的判斷,現在投入桌面外掛等於選擇跟著版本走,所以第一個外掛該壓小:一個面板、一個明確用途,並把每段程式碼該跑在哪個程序寫進註解。理由不是功能做不到,而是 API 還在動,包袱越小越容易跟上每一次變動。

也有該等的人。官方沒有給實驗轉正的時間表,也還沒有一個集中發現桌面外掛的地方,發布就是 npm、發現要靠社群口耳相傳;如果你要的是穩定的全公司流程,現在還不到承諾的時機。實際動手把外掛建起來跑的體驗、打包與熱重載在真實專案裡的順手程度,也要等有人走過才算數,這是目前任何文件都回答不了的部分。

OpenCode 這一年的能見度不低,連 手機監看代理進度的工具 都把它與 Claude Code、Codex 並列支援,代理工具之間的互操作也成了顯學,從 把工作派給不同模型的交換層 到跨工具共享的專案記憶,都在解同一類問題。對既有外掛作者,2.2 給了一條新路,也給了一份升級功課;對還在觀望的人,這次更新至少把桌面版的擴充邊界講清楚了。想跟這條產品線的人,先讀懂視窗與主程序的分工,再談面板要長什麼樣。

Sliven 褚崇名
Sliven 褚崇名

每日分享科技新知、免費資源以及 WordPress、虛擬主機相關主題,任何問題歡迎在科技月球下方留言,或是發送 Email 至 [email protected] 與我聯繫。

文章: 2206

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *


Share to...