opencli-autofix

opencli-autofix

热门

当 opencli 命令失败时,自动修复损坏的 OpenCLI 适配器。加载此技能后,它会引导你收集跟踪工件、修补适配器、重试,并在验证修复后提交上游 GitHub 问题。适用于任何 AI 代理。

2.6万Star
2565Fork
更新于 2026/6/27
SKILL.md
readonly只读
name
opencli-autofix
description

当 opencli 命令失败时,自动修复损坏的 OpenCLI 适配器。加载此技能后,它会引导你收集跟踪工件、修补适配器、重试,并在验证修复后提交上游 GitHub 问题。适用于任何 AI 代理。

OpenCLI AutoFix — 自动适配器自我修复

opencli 命令因网站更改了 DOM、API 或响应模式而失败时,自动诊断、修复适配器并重试——不要仅仅报告错误。

安全边界

在开始任何修复之前,检查这些硬性停止条件:

  • AUTH_REQUIRED(退出码 77)— 停止。 不要修改代码。告诉用户在 Chrome 中登录该网站。
  • BROWSER_CONNECT(退出码 69)— 停止。 不要修改代码。告诉用户运行 opencli doctor
  • 验证码 / 速率限制停止。 不是适配器问题。

范围限制:

  • 仅修改跟踪 summary.md 前置元数据中 adapterSourcePath 指向的文件 — 这是权威的适配器位置(可能是仓库中的 clis/<site>/ 或 npm 安装的 ~/.opencli/clis/<site>/
  • 绝不修改 src/extension/tests/package.jsontsconfig.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 重大重新设计 可能需要完全重写适配器

需要回答的关键问题:

  1. 适配器试图做什么?(读取 adapterSourcePath 处的文件)
  2. 失败时页面看起来如何?(读取 summary.md,必要时读取 state/
  3. 发生了哪些网络请求?(读取 summary.md 中的 Failed Network,必要时读取 network.jsonl
  4. 适配器期望的内容与页面提供的内容之间的差距是什么?

步骤 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"]' })

修补规则

  1. 做最小更改 — 只修复损坏的部分,不要重构
  2. 保持相同的输出结构columns 和返回格式必须保持兼容
  3. 优先使用 API 而非 DOM 抓取 — 如果在探索过程中发现 JSON API,则切换到它
  4. 仅使用 @jackwener/opencli/* 导入 — 绝不添加第三方包导入
  5. 修补后测试 — 再次运行命令以验证
  6. 绝不放宽 verify/<cmd>.json 的 fixtures 来掩盖失败。 失败的 patterns / notEmpty / mustNotContain / mustBeTruthy 规则意味着适配器的输出已损坏。收紧适配器以产生正确的值;不要放宽 fixture 以接受损坏的值。在修复期间编辑 fixture 的唯一合法理由是当网站本身改变了形态(例如 URL 格式迁移)——在这种情况下更新 fixture 并在 ~/.opencli/sites/<site>/notes.md 中记录更改。否则编辑 fixture 就是在掩盖静默的正确性回归。

步骤 5:验证修复

# 正常运行命令
opencli <site> <command> [args...]

如果仍然失败,返回步骤 1 并收集新的跟踪。你有 3 轮修复的预算(跟踪 → 修复 → 重试)。如果修复后相同错误仍然存在,尝试不同的方法。3 轮后停止并报告已尝试的内容。

步骤 6:提交上游问题

如果重试通过,本地适配器已与上游偏离。提交 GitHub 问题以便修复流回 jackwener/OpenCLI

不要为以下情况提交:

  • AUTH_REQUIREDBROWSER_CONNECTARGUMENTCONFIG — 环境/使用问题,不是适配器错误
  • 验证码或速率限制 — 上游无法修复
  • 你实际上无法修复的失败(3 轮已耗尽)

仅在验证本地修复后提交 — 重试必须首先通过。

步骤:

  1. 从已有的跟踪摘要准备问题内容:
    • 标题: [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 在验证本地修复后提交。_
  1. 在提交前询问用户。 向他们展示草稿标题和正文。仅在他们确认后才继续。

  2. 如果用户批准且 gh auth status 成功:

gh issue create --repo jackwener/OpenCLI \
  --title "[autofix] <site>/<command>: <error_code>" \
  --body "<上述正文>"

如果 gh 未安装或未认证,告诉用户并跳过——不要报错退出。

何时停止

硬性停止(不要修改代码):

  • AUTH_REQUIRED / BROWSER_CONNECT — 环境问题,不是适配器错误
  • 站点需要验证码 — 无法自动化处理
  • 速率限制 / 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 "..."