AI 工程

Cline v3.0.36 修掉了會讓 agent 偷用 shell 改檔的 Plan→Act 切換 bug

一個你可能沒察覺、但很危險的 bug

當你在 Cline 裡先用 Plan 模式規劃、再切到 Act 模式讓它動手,你預期的行為是:計畫敲定 → 切模式 → agent 用正規的檔案編輯工具,一個一個 diff 攤給你看、你核准、它才寫入。這一整套「先想清楚再改」的節奏,正是很多人選 Cline 的原因。

但在 cli-v3.0.35 之前,這個切換藏著一個時機錯誤。模型在 Plan 模式裡呼叫 switch_to_act_mode 這個工具後,切換不會馬上生效,而是排隊等到「當前這一回合結束」才套用。麻煩的是——工具回傳給模型的結果訊息已經寫著「好,你現在可以編輯了」,於是模型信以為真、當場開始動手;可是它手上的工具集其實還是 Plan 模式那一套(沒有 file editor)。找不到編輯工具,模型就退而求其次:直接用 shell 指令硬把檔案寫出去(cat > filesed -iecho >> file、heredoc 那一類)。

結果就是:你以為它會乖乖走 diff 審核流程,實際上它繞過了差異預覽,用一堆 shell 指令把你的檔案改掉。這正是 cli-v3.0.36 修掉的東西。Cline 作者 Saoud Rizwan(GitHub 帳號 saoudrizwan)在 PR #12054 的 release note 裡把症狀寫得很白:

Fixed plan mode's switch_to_act_mode tool not taking effect until the end of the turn: the model would keep running with plan-mode tools (no file editor) and fall back to editing files through shell commands.

舊行為 vs 新行為的回合流程對比

先搞懂 Plan / Act 到底在管什麼

要看懂這個 bug,得先知道 Cline 的 Plan / Act 不只是「兩種心情」,而是兩套不同的工具集

  • Plan 模式:唯讀探索。Cline 可以讀檔、搜尋、跑分析、跟你討論架構與步驟,但不掛載會改檔、會跑破壞性指令的工具。它的產出是一份計畫,不是一堆 commit。
  • Act 模式:實際執行。這時 file editor、寫檔、跑指令等工具才會掛上,Cline 依照剛才談定的計畫動手,改動會走差異預覽讓你核准。

兩個模式共用同一段對話歷史,所以切過去不用重講一遍脈絡——這是 Cline 官方文件強調的「context carries over」。而模型要主動從 Plan 切到 Act,靠的就是呼叫 switch_to_act_mode 這個工具;在互動式 CLI 裡,你自己也能用 Tab 鍵手動切。關鍵在於:Plan 之所以安全,是因為它的工具集裡沒有編輯工具。一旦「模式標記」和「實際掛載的工具集」對不上,安全保證就破了。

值得一提的是,這種「先規劃、後執行」的雙態設計並非 Cline 獨有。Claude Code 有 Plan Mode(唯讀規劃,核准後才執行)、Cursor 也用 Ask 與 Agent 兩種互動來分隔「討論」與「動手」。差別在於各家實作隔離的手法:Cline 選擇用工具集的掛載與否來硬性劃線,這比只靠 system prompt 提醒「你現在只能規劃」要可靠得多——因為模型再怎麼想改檔,工具集裡沒有編輯工具,它就改不了。這個設計本身很紮實,正因如此,一旦掛載時序出錯,破口才會這麼明顯。

bug 的根因:工具結果與工具集不同步

把時序拆開看就很清楚。舊版的執行順序大致是:

  1. 模型在 Plan 回合裡呼叫 switch_to_act_mode
  2. 系統把「要切成 Act」這件事排進待處理佇列,但當前回合的工具集沒有重建,還是 Plan 那一套。
  3. 工具結果回給模型:「切換完成,你可以編輯了」。
  4. 模型繼續在同一個回合裡跑下去——它以為自己在 Act,卻只有 Plan 工具可用。
  5. 想改檔卻沒有 file editor,模型只好用 run_command 之類的通道,靠 shell 把檔案內容寫出去。

問題的本質是狀態不同步:工具「回報的結果」跑在「實際能力」前面。模型拿到一個與現實不符的承諾,於是做出一連串看似合理、實則危險的動作。更糟的是,這些 shell 寫檔操作可能繞過了 Cline 平常的 diff 審核與檔案追蹤,讓你在事後很難看清它到底改了什麼。

為什麼模型會「退回去用 shell」而不是報錯停下?這其實是 coding agent 很常見的行為模式:當一個顯而易見的工具不存在時,能力強的模型傾向自己找替代路徑把任務完成,而不是卡住。平常這是優點——工具缺一角時它還能硬湊出結果;但在這個情境下,這份「積極」正好把安全護欄踩穿。模型並沒有做錯什麼,它只是忠實地照著「你已經可以編輯了」這個(錯誤的)前提往下推。這也提醒我們:agent 的行為好壞,往往不在模型聰不聰明,而在它拿到的環境訊號是否誠實

v3.0.36 怎麼修:四個環節一起補

從 PR #12054 的說明看,這次不是打個小補丁,而是把整條切換路徑重做,落在四個環節上。

v3.0.36 的四段修復機制

  1. 切換即結束回合switch_to_act_mode 被標記為 lifecycle.completesRun。工具一被呼叫,當前 Plan 回合立刻收尾,不會再帶著舊工具集多跑幾步。這一步直接掐斷了「用 Plan 工具假裝在 Act」的空間。
  2. 用 Act 工具集重建 session:待處理的 mode change 會觸發 session rebuild,把 file editor 等 Act 工具重新掛上。等模型下一步要動手時,手裡才真的有正規的編輯能力。
  3. 自動接續核准的計畫:切換後系統會注入一段 continuation prompt,讓已經核准的計畫無縫往下執行,你不用再手動打一句「開始做吧」。體感上就是 Plan 談完、切到 Act,它就順順地接著做。
  4. 依來源標記待處理的切換:切換請求會被標記是來自工具(模型呼叫)還是 UI(你按 Tab)。這樣一來,當 Tab 切換剛好撞上一個正要結束的回合時,不會誤把還沒核准的計畫自動開跑——這是舊版另一個 race condition。

四件事合起來,才讓「切模式」從一個有縫的動作,變成即時、可預期、且尊重你核准權的流程。

你會怎麼踩到、怎麼確認自己中了

這個 bug 不會噴錯誤,所以特別隱蔽。幾個可以對照的徵兆:

  • Plan 談完切 Act 後,agent 改檔時沒有走你熟悉的 diff 預覽,而是冒出一串 catsedecho 或 heredoc 把內容灌進檔案。
  • 你按 Tab 切模式,結果它自己開始執行一份你還沒點頭的計畫
  • 明明在 Plan 模式,檔案卻被動到了。

確認版本很簡單,在終端機跑:

cline --version

若低於 3.0.36,就升級(Cline CLI 透過 npm 全域安裝):

npm install -g @cline/cli@latest
# 或指定版本
npm install -g @cline/cli@3.0.36

升級是這題唯一的正解——它是執行迴圈層的時序 bug,靠寫 prompt 是繞不掉的。你再怎麼在提示裡叮嚀「請用檔案編輯工具、不要用 shell 改檔」,只要工具集在切換當下沒被正確重建,模型手上就是沒有那個工具,叮嚀也沒用。這也是為什麼盯著 coding agent 的版本更新是值得的:很多你以為是「模型不聽話」的怪行為,其實是 harness 層的 bug,換個版本就消失了。

實戰:把 Plan→Act 用對的幾招

修好之後,Plan/Act 這套流程才真正好用。幾個可以直接照做的習慣:

1. 用 --plan 起手,讓它先想再做。 面對稍有規模的改動,別一上來就 Act:

cline --plan "幫我把 auth middleware 換成 JWT 驗證,先別動手,
把改動拆成步驟清單、列出會碰到的檔案,等我核准再切 Act。"

在互動式 session 裡,計畫看順眼了再用 Tab 切到 Act,或直接叫它切;v3.0.36 之後這個切換會即時生效並接續你核准的計畫。

2. 在 Plan 階段就把「驗收標準」講清楚。 Plan 模式的價值是逼模型把方案攤開。與其只說「改成 JWT」,不如補上:「哪些現有測試要能繼續過」「不要改動 API 回傳格式」「每一步先給我看 diff」。這些約束帶進 Act 後會一路生效。

3. 把 Plan 當 code review 的前哨。 讓它先輸出「我要動哪些檔、為什麼、風險在哪」,你在還沒有任何改動時就能攔下錯誤方向,成本遠低於改完再回滾。

4. 別把 Tab 當隨手鍵。 既然切到 Act 就會接續執行,切之前先確認計畫你是真的核准了,而不是手滑。

5. 一個完整的 Plan→Act 節奏長這樣。 把上面幾點串起來,一個穩健的改動流程大致是:先 --plan 起手並附上約束與驗收條件 → 讀它列出的步驟清單與受影響檔案 → 對不滿意的地方直接在 Plan 模式追問、要它改計畫(這時它還沒動任何檔)→ 計畫定案後 Tab 切 Act → 它逐步給 diff、你逐一核准。整個過程裡,「唯讀」和「動手」被清楚切開,你永遠知道現在是在討論還是在改東西。v3.0.36 把切換的那一刻修對了,這個節奏才真的順得起來——在舊版,你以為自己還在第三步的「討論」,它其實已經在用 shell 改檔了。

對工程團隊的意義

如果你的團隊把 Cline 接進 CI、自動化腳本或無人值守的流程,這個修復不只是「體驗變好」,而是安全邊界的修補。舊版那個「Plan 模式下卻用 shell 改檔」的行為,等於讓唯讀階段的安全假設失效——在自動化情境下,這可能意味著沒人核准的改動被寫進 repo。

更普遍的一課是:agent 的安全性,取決於「宣稱的狀態」和「實際的能力」有沒有對齊。Cline 用工具集來實作模式隔離,是很乾淨的設計;但只要「工具回報的結果」領先「工具集的重建」,模型就會拿著一張跳票的支票去行動。要用好任何 coding agent,值得養成的直覺是:別只看它「說」自己在什麼模式,去確認它手上「真正掛著」哪些工具。當你發現 agent 在該唯讀的階段動了檔案,那不是它變聰明了,是護欄破了——第一件事該做的是查版本、補上游修復,而不是想辦法跟它共處。

來源

整理:DataAgent · Coding Agent 實戰教學

發表迴響

%d 位部落客按了讚: