Automatically fix broken OpenCLI adapters when commands fail. Load this skill when an opencli command fails — it guides you through collecting a trace artifact, patching the adapter, retrying, and filing an upstream GitHub issue after a verified fix. Works with any AI agent.
OpenCLI AutoFix — 自動轉接器自我修復
當 opencli 指令因網站變更 DOM、API 或回應結構而失敗時,自動診斷、修復轉接器並重試 — 而不只是回報錯誤。
安全邊界
開始任何修復前,請檢查這些硬性停止條件:
AUTH_REQUIRED(退出碼 77) — 停止。 不要修改程式碼。告知使用者需在 Chrome 中登入該網站。BROWSER_CONNECT(退出碼 69) — 停止。 不要修改程式碼。告知使用者執行opencli doctor。- CAPTCHA / 速率限制 — 停止。 這不是轉接器問題。
範圍限制:
- 僅修改追蹤記錄
summary.md前置資料中的adapterSourcePath檔案 — 這是權威的轉接器位置(可能位於儲存庫的clis/<site>/或 npm 安裝的~/.opencli/clis/<site>/) - 絕不修改
src/、extension/、tests/、package.json或tsconfig.json
重試次數上限: 每次失敗最多 3 次修復回合。若 3 輪診斷 → 修復 → 重試仍未解決,請停止並回報嘗試過的步驟。
前置需求
opencli doctor # 驗證擴充功能與背景程式的連線
何時使用此技能
當 opencli <site> <command> 因可修復的錯誤而失敗時使用:
- SELECTOR — 找不到元素(DOM 變更)
- EMPTY_RESULT — 無資料回傳(API 回應變更)
- API_ERROR / NETWORK — 端點移動或損壞
- PAGE_CHANGED — 頁面結構不再相符
- COMMAND_EXEC — 轉接器邏輯執行時期錯誤
- TIMEOUT — 頁面載入方式不同,轉接器等待錯誤的項目
進入修復前:「空」≠「損壞」
EMPTY_RESULT — 有時結構上有效的 SELECTOR 回傳空值 — 通常不是轉接器錯誤。平台在反爬蟲機制下會主動減少結果,而網站回傳「找不到」不代表內容真的不存在。在投入修復回合前先排除此情況:
- 使用替代查詢或進入點重試。 若
opencli xiaohongshu search "X"回傳 0 但opencli xiaohongshu search "X 攻略"回傳 20,則轉接器正常 — 平台只是對第一個查詢進行了結果塑造。 - 在一般 Chrome 分頁中抽查。 若資料在使用者自己的瀏覽器中可見,但轉接器回傳空值,問題通常是驗證狀態、速率限制或軟封鎖 — 而非程式碼錯誤。解決方式是
opencli doctor/ 重新登入,而非編輯原始碼。 - 留意軟 404。 小紅書、微博、抖音等網站會在項目隱藏或刪除時回傳 HTTP 200 與空內容,而非真正的 404。快照看起來結構正確。延遲 2-3 秒重試通常能區分「暫時隱藏」與「真的消失」。
- 「0 筆結果」本身就是答案。 若轉接器成功到達搜尋端點、取得 HTTP 200,且平台回傳
results: [],這是有效答案 — 向使用者回報「此查詢無相符結果」,而非修補轉接器。
僅在空值/選擇器缺失結果可跨重試與替代進入點重現時,才繼續進行步驟 1。否則你只是在修補一個正常運作的轉接器來追逐雜訊,而修補後的版本會破壞下一個正常路徑。
步驟 1:收集追蹤上下文
使用保留失敗追蹤的方式執行失敗指令:
opencli <site> <command> [args...] --trace retain-on-failure 2>trace-error.yaml
失敗時,stderr 包含一般錯誤信封加上一個小型 trace 區塊:
ok: false
error:
code: SELECTOR
message: "Could not find element: .old-selector"
trace:
schemaVersion: 1
opencliVersion: "..."
traceId: "..."
dir: "/path/to/.opencli/profiles/default/traces/..."
summaryPath: "/path/to/.opencli/profiles/default/traces/.../summary.md"
receiptPath: "/path/to/.opencli/profiles/default/traces/.../receipt.json"
先讀取 summaryPath。它是 LLM 導向的進入點,並包含前置資料:
---
schemaVersion: 1
opencliVersion: "..."
traceId: "..."
status: failure
site: "example"
command: "example/search"
adapterSourcePath: "/path/to/clis/example/search.js"
errorCode: "SELECTOR"
errorMessage: "Could not find element: .old-selector"
---
成品目錄包含:
summary.md # 從這裡開始
receipt.json # 機器可讀的追蹤收據
trace.jsonl # 完整的編輯時間軸
network.jsonl # 編輯過的網路事件
console.jsonl # 編輯過的控制台事件
state/ # 最終快照(如有)
screenshots/ # 最終螢幕截圖(如有)
若你將 stderr 重新導向至檔案,請讀取該檔案並複製 trace.summaryPath。
不要要求使用者使用舊版診斷環境變數重新執行。追蹤記錄是修復的證據路徑。
步驟 2:分析失敗原因
讀取追蹤摘要與轉接器原始碼。分類根本原因:
| 錯誤碼 | 可能原因 | 修復策略 |
|---|---|---|
| SELECTOR | DOM 重組、類別/ID 重新命名 | 探索當前 DOM → 尋找新選擇器 |
| EMPTY_RESULT | API 回應結構變更,或資料移動 | 檢查網路 → 尋找新回應路徑 |
| API_ERROR | 端點 URL 變更、需要新參數 | 透過網路攔截發現新 API |
| AUTH_REQUIRED | 登入流程變更、Cookie 過期 | 停止 — 告知使用者登入,不要修改程式碼 |
| TIMEOUT | 頁面載入方式不同、旋轉圖示/延遲載入 | 新增/更新等待條件 |
| PAGE_CHANGED | 重大重新設計 | 可能需要完整重寫轉接器 |
需要回答的關鍵問題:
- 轉接器嘗試做什麼?(讀取
adapterSourcePath的檔案) - 失敗時頁面看起來如何?(讀取
summary.md,必要時讀取state/) - 發生了哪些網路請求?(讀取
summary.md中的Failed Network,必要時讀取network.jsonl) - 轉接器預期與頁面實際提供之間的差距是什麼?
步驟 3:探索當前網站
使用 opencli browser 檢查即時網站。絕不使用損壞的轉接器 — 它只會再次失敗。
DOM 變更(SELECTOR 錯誤)
# 開啟頁面並檢查當前 DOM
opencli browser open https://example.com/target-page && opencli browser state
# 尋找符合轉接器意圖的元素
# 將快照與轉接器預期的內容進行比較
API 變更(API_ERROR、EMPTY_RESULT)
# 使用網路攔截器開啟頁面,然後手動觸發動作
opencli browser open https://example.com/target-page && opencli browser state
# 互動以觸發 API 呼叫
opencli browser click <N> && opencli browser network
# 根據請求主體應有的欄位縮小範圍
opencli browser network --filter author,text,likes
# 檢查特定 API 回應(key 是預設 JSON 輸出中的 `key` 欄位)
opencli browser network --detail <key>
步驟 4:修補轉接器
從追蹤摘要前置資料中的 adapterSourcePath 讀取轉接器原始檔,並進行有針對性的修復。此路徑是權威的 — 可能在儲存庫(clis/)或使用者本地(~/.opencli/clis/)。
使用 Read 工具讀取 summary.md 前置資料中的確切路徑。
常見修復
選擇器更新:
// 之前:page.evaluate('document.querySelector(".old-class")...')
// 之後:page.evaluate('document.querySelector(".new-class")...')
API 端點變更:
// 之前:const resp = await page.evaluate(`fetch('/api/v1/old-endpoint')...`)
// 之後:const resp = await page.evaluate(`fetch('/api/v2/new-endpoint')...`)
回應結構變更:
// 之前:const items = data.results
// 之後:const items = data.data.items // API 現在巢狀在 "data" 下
等待條件更新:
// 之前:await page.wait({ selector: '.loading-spinner', hidden: true })
// 之後:await page.wait({ selector: '[data-loaded="true"]' })
修補規則
- 做最小變更 — 只修復損壞的部分,不要重構
- 保持相同的輸出結構 —
columns與回傳格式必須保持相容 - 優先使用 API 而非 DOM 抓取 — 若在探索過程中發現 JSON API,請切換使用
- 僅使用
@jackwener/opencli/*匯入 — 絕不新增第三方套件匯入 - 修補後測試 — 再次執行指令以驗證
- 絕不為了讓失敗消失而放寬
verify/<cmd>.json的測試條件。 失敗的patterns/notEmpty/mustNotContain/mustBeTruthy規則表示轉接器的輸出有問題。應加強轉接器使其產生正確的值;不要放寬測試條件來接受錯誤的值。修復期間編輯測試條件的唯一正當理由是網站本身改變了形狀(例如 URL 格式遷移)— 在這種情況下更新測試條件,並在~/.opencli/sites/<site>/notes.md中記錄變更。否則編輯測試條件就是在掩蓋無聲的正確性回歸。
步驟 5:驗證修復
# 正常執行指令
opencli <site> <command> [args...]
若仍失敗,回到步驟 1 收集新的追蹤記錄。你有 3 次修復回合的預算(追蹤 → 修復 → 重試)。若修復後相同錯誤持續存在,請嘗試不同方法。3 回合後,停止並回報嘗試過的步驟。
步驟 6:提交上游議題
若重試通過,表示本地轉接器已偏離上游。提交 GitHub 議題,讓修復回饋到 jackwener/OpenCLI。
不要提交的情況:
AUTH_REQUIRED、BROWSER_CONNECT、ARGUMENT、CONFIG— 環境/使用問題,非轉接器錯誤- CAPTCHA 或速率限制 — 上游無法修復
- 你實際上無法修復的失敗(3 回合耗盡)
僅在本地修復驗證通過後提交 — 必須先通過重試。
程序:
- 從你已有的追蹤摘要準備議題內容:
- 標題:
[autofix] <site>/<command>: <error_code>(例如[autofix] zhihu/hot: SELECTOR) - 內容(使用此範本):
- 標題:
## 摘要
OpenCLI autofix 已在本地修復此轉接器,且重試通過。
## 轉接器
- 網站:`<site>`
- 指令:`<command>`
- OpenCLI 版本:`<version from opencli --version>`
## 原始失敗
- 錯誤碼:`<error_code>`
~~~
<error_message>
~~~
## 本地修復摘要
~~~
<1-2 句說明你變更了什麼及原因>
~~~
_此議題由 OpenCLI autofix 在驗證本地修復後提交。_
-
提交前先詢問使用者。 向他們展示草稿標題與內容。僅在他們確認後才繼續。
-
若使用者同意且
gh auth status成功:
gh issue create --repo jackwener/OpenCLI \
--title "[autofix] <site>/<command>: <error_code>" \
--body "<上述內容>"
若 gh 未安裝或未驗證,告知使用者並跳過 — 不要報錯。
何時停止
硬性停止(不要修改程式碼):
- AUTH_REQUIRED / BROWSER_CONNECT — 環境問題,非轉接器錯誤
- 網站需要 CAPTCHA — 無法自動化處理
- 速率限制 / IP 被封鎖 — 非轉接器問題
軟性停止(嘗試後回報):
- 3 次修復回合耗盡 — 停止,回報嘗試了什麼及什麼失敗了
- 功能完全移除 — 資料已不存在
- 重大重新設計 — 需要透過
opencli-adapter-author技能完整重寫轉接器
在所有停止情況下,清楚地向使用者說明情況,而不是進行無效的修補。
範例修復會話
1. 使用者執行:opencli zhihu hot
→ 失敗:SELECTOR "Could not find element: .HotList-item"
2. AI 執行:opencli zhihu hot --trace retain-on-failure 2>trace-error.yaml
→ 取得包含最終狀態與失敗動作證據的追蹤摘要
3. AI 讀取摘要/狀態:頁面已載入但使用 ".HotItem" 而非 ".HotList-item"
4. AI 探索:opencli browser open https://www.zhihu.com/hot && opencli browser state
→ 確認新類別名稱 ".HotItem" 帶有子元素 ".HotItem-content"
5. AI 修補:編輯 `adapterSourcePath` 的轉接器 — 將 ".HotList-item" 替換為 ".HotItem"
6. AI 驗證:opencli zhihu hot
→ 成功:回傳熱門話題
7. AI 準備上游議題草稿,展示給使用者
8. 使用者同意 → AI 執行:gh issue create --repo jackwener/OpenCLI --title "[autofix] zhihu/hot: SELECTOR" --body "..."






