qiaomu-opencli-autofix

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

OpenCLI AutoFix — Automatic Adapter Self-Repair

OpenCLI AutoFix — 适配器自动自修复

When an
opencli
command fails because a website changed its DOM, API, or response schema, automatically diagnose, fix the adapter, and retry — don't just report the error.
opencli
命令因为网站修改了DOM、API或响应结构而失败时,自动诊断、修复适配器并重试,而不是仅报错。

Safety Boundaries

安全边界

Before starting any repair, check these hard stops:
  • AUTH_REQUIRED
    (exit code 77) — STOP. Do not modify code. Tell the user to log into the site in Chrome.
  • BROWSER_CONNECT
    (exit code 69) — STOP. Do not modify code. Tell the user to run
    opencli doctor
    .
  • CAPTCHA / rate limitingSTOP. Not an adapter issue.
Scope constraint:
  • Only modify the file at
    RepairContext.adapter.sourcePath
    — this is the authoritative adapter location (may be
    clis/<site>/
    in repo or
    ~/.opencli/clis/<site>/
    for npm installs)
  • Never modify
    src/
    ,
    extension/
    ,
    tests/
    ,
    package.json
    , or
    tsconfig.json
Retry budget: Max 3 repair rounds per failure. If 3 rounds of diagnose → fix → retry don't resolve it, stop and report what was tried.
启动任何修复操作前,请先检查以下强制停止规则:
  • AUTH_REQUIRED
    (退出码 77)——立即停止,不要修改代码,告知用户需要在Chrome中登录对应网站。
  • BROWSER_CONNECT
    (退出码 69)——立即停止,不要修改代码,告知用户运行
    opencli doctor
    命令。
  • CAPTCHA / 限流——立即停止,不属于适配器问题。
范围限制:
  • 仅允许修改
    RepairContext.adapter.sourcePath
    路径下的文件
    ——这是官方的适配器存储路径,可能是代码仓库中的
    clis/<site>/
    路径,也可能是npm安装对应的
    ~/.opencli/clis/<site>/
    路径
  • 禁止修改
    src/
    extension/
    tests/
    package.json
    tsconfig.json
    文件
重试限额:每次故障最多允许3轮修复。如果3轮“诊断→修复→重试”流程后问题仍未解决,停止操作并告知用户已尝试的方案。

Prerequisites

前置条件

bash
opencli doctor    # Verify extension + daemon connectivity
bash
opencli doctor    # 验证扩展与守护进程的连通性

When to Use This Skill

何时使用此技能

Use when
opencli <site> <command>
fails with repairable errors:
  • SELECTOR — element not found (DOM changed)
  • EMPTY_RESULT — no data returned (API response changed)
  • API_ERROR / NETWORK — endpoint moved or broke
  • PAGE_CHANGED — page structure no longer matches
  • COMMAND_EXEC — runtime error in adapter logic
  • TIMEOUT — page loads differently, adapter waits for wrong thing
opencli <site> <command>
执行失败且属于可修复错误时使用:
  • SELECTOR — 元素未找到(DOM结构变更)
  • EMPTY_RESULT — 无返回数据(API响应结构变更)
  • API_ERROR / NETWORK — 接口地址变更或失效
  • PAGE_CHANGED — 页面结构与适配逻辑不匹配
  • COMMAND_EXEC — 适配器逻辑运行时错误
  • TIMEOUT — 页面加载逻辑变更,适配器等待的对象错误

Before Entering Repair: "Empty" ≠ "Broken"

进入修复流程前:“空结果”≠“适配器损坏”

EMPTY_RESULT
— and sometimes a structurally-valid
SELECTOR
that returns nothing — is often not an adapter bug. Platforms actively degrade results under anti-scrape heuristics, and a "not found" response from the site doesn't mean the content is actually missing. Rule this out before committing to a repair round:
  • Retry with an alternative query or entry point. If
    opencli xiaohongshu search "X"
    returns 0 but
    opencli xiaohongshu search "X 攻略"
    returns 20, the adapter is fine — the platform was shaping results for the first query.
  • Spot-check in a normal Chrome tab. If the data is visible in the user's own browser but the adapter comes back empty, the issue is usually authentication state, rate limiting, or a soft block — not a code bug. The fix is
    opencli doctor
    / re-login, not editing source.
  • Look for soft 404s. Sites like xiaohongshu / weibo / douyin return HTTP 200 with an empty payload instead of a real 404 when an item is hidden or deleted. The snapshot will look structurally correct. A retry 2-3 seconds later often distinguishes "temporarily hidden" from "actually gone".
  • "0 results" from a search is an answer. If the adapter successfully reached the search endpoint, got an HTTP 200, and the platform returned
    results: []
    , that is a valid answer — report it to the user as "no matches for this query" rather than patching the adapter.
Only proceed to Step 1 if the empty/selector-missing result is reproducible across retries and alternative entry points. Otherwise you're patching a working adapter to chase noise, and the patched version will break the next working path.
EMPTY_RESULT
——有时甚至是结构合法但返回空结果的
SELECTOR
错误——通常不是适配器bug。平台会基于反爬策略主动限制返回结果,网站返回“未找到”不代表内容真的不存在。在启动修复流程前请先排除以下情况:
  • 使用替代查询词或入口重试。如果
    opencli xiaohongshu search "X"
    返回0条结果,但
    opencli xiaohongshu search "X 攻略"
    返回20条结果,说明适配器正常,只是平台对第一个查询做了结果限制。
  • 在普通Chrome标签页中手动核验。如果用户自己的浏览器中可以看到数据,但适配器返回空结果,通常是登录状态、限流或者软封禁问题,不是代码bug。解决方案是运行
    opencli doctor
    或重新登录,而非修改源码。
  • 排查软404问题。小红书、微博、抖音等网站在内容隐藏或删除时会返回HTTP 200状态码和空 payload,而非真实的404,快照看起来结构是完全正常的。等待2-3秒后重试通常可以区分“临时隐藏”和“永久删除”。
  • 搜索返回“0条结果”本身就是有效结果。如果适配器成功访问了搜索接口,获得HTTP 200响应,且平台返回
    results: []
    ,这属于合法结果,应该告知用户“该查询无匹配结果”,而非修改适配器。
只有当空结果/选择器未找到的问题在多次重试和更换入口后仍可复现时,才继续执行步骤1。否则你就是在给正常工作的适配器打补丁适配噪声,修改后的版本会破坏后续正常的使用路径。

Step 1: Collect Diagnostic Context

步骤1:收集诊断上下文

Run the failing command with diagnostic mode enabled:
bash
OPENCLI_DIAGNOSTIC=1 opencli <site> <command> [args...] 2>diagnostic.json
This outputs a
RepairContext
JSON between
___OPENCLI_DIAGNOSTIC___
markers in stderr:
json
{
  "error": {
    "code": "SELECTOR",
    "message": "Could not find element: .old-selector",
    "hint": "The page UI may have changed."
  },
  "adapter": {
    "site": "example",
    "command": "example/search",
    "sourcePath": "/path/to/clis/example/search.ts",
    "source": "// full adapter source code"
  },
  "page": {
    "url": "https://example.com/search",
    "snapshot": "// DOM snapshot with [N] indices",
    "networkRequests": [],
    "consoleErrors": []
  },
  "timestamp": "2025-01-01T00:00:00.000Z"
}
Parse it:
bash
undefined
启用诊断模式运行失败的命令:
bash
OPENCLI_DIAGNOSTIC=1 opencli <site> <command> [args...] 2>diagnostic.json
该命令会在标准错误流的
___OPENCLI_DIAGNOSTIC___
标记之间输出
RepairContext
JSON内容:
json
{
  "error": {
    "code": "SELECTOR",
    "message": "Could not find element: .old-selector",
    "hint": "The page UI may have changed."
  },
  "adapter": {
    "site": "example",
    "command": "example/search",
    "sourcePath": "/path/to/clis/example/search.ts",
    "source": "// full adapter source code"
  },
  "page": {
    "url": "https://example.com/search",
    "snapshot": "// DOM snapshot with [N] indices",
    "networkRequests": [],
    "consoleErrors": []
  },
  "timestamp": "2025-01-01T00:00:00.000Z"
}
解析诊断数据:
bash
undefined

Extract JSON between markers from stderr output

从标准错误输出中提取标记之间的JSON内容

cat diagnostic.json | sed -n '/OPENCLI_DIAGNOSTIC/{n;p;}'
undefined
cat diagnostic.json | sed -n '/OPENCLI_DIAGNOSTIC/{n;p;}'
undefined

Step 2: Analyze the Failure

步骤2:分析故障原因

Read the diagnostic context and the adapter source. Classify the root cause:
Error CodeLikely CauseRepair Strategy
SELECTORDOM restructured, class/id renamedExplore current DOM → find new selector
EMPTY_RESULTAPI response schema changed, or data movedCheck network → find new response path
API_ERROREndpoint URL changed, new params requiredDiscover new API via network intercept
AUTH_REQUIREDLogin flow changed, cookies expiredSTOP — tell user to log in, do not modify code
TIMEOUTPage loads differently, spinner/lazy-loadAdd/update wait conditions
PAGE_CHANGEDMajor redesignMay need full adapter rewrite
Key questions to answer:
  1. What is the adapter trying to do? (Read the
    source
    field)
  2. What did the page look like when it failed? (Read the
    snapshot
    field)
  3. What network requests happened? (Read
    networkRequests
    )
  4. What's the gap between what the adapter expects and what the page provides?
读取诊断上下文和适配器源码,归类根因:
错误码可能原因修复策略
SELECTORDOM结构重构,class/id重命名探查当前DOM → 找到新的选择器
EMPTY_RESULTAPI响应结构变更,或数据位置迁移检查网络请求 → 找到新的响应路径
API_ERROR接口URL变更,需要新参数通过网络抓包发现新的API
AUTH_REQUIRED登录流程变更,cookie过期立即停止——告知用户登录,不要修改代码
TIMEOUT页面加载逻辑变更, spinner/懒加载逻辑变更添加/更新等待条件
PAGE_CHANGED网站大幅改版可能需要完整重写适配器
需要明确的核心问题:
  1. 适配器的预期功能是什么?(读取
    source
    字段)
  2. 故障发生时页面的实际状态是什么?(读取
    snapshot
    字段)
  3. 发生了哪些网络请求?(读取
    networkRequests
    字段)
  4. 适配器的预期输出和页面实际提供的内容之间的差异是什么?

Step 3: Explore the Current Website

步骤3:探查当前网站状态

Use
opencli browser
to inspect the live website. Never use the broken adapter — it will just fail again.
使用
opencli browser
检查实时网站状态,不要使用损坏的适配器——它只会再次失败。

DOM changed (SELECTOR errors)

DOM变更(SELECTOR错误)

bash
undefined
bash
undefined

Open the page and inspect current DOM

打开页面并检查当前DOM

opencli browser open https://example.com/target-page && opencli browser state
opencli browser open https://example.com/target-page && opencli browser state

Look for elements that match the adapter's intent

查找符合适配器功能预期的元素

Compare the snapshot with what the adapter expects

对比快照和适配器的预期结构

undefined
undefined

API changed (API_ERROR, EMPTY_RESULT)

API变更(API_ERROR、EMPTY_RESULT错误)

bash
undefined
bash
undefined

Open page with network interceptor, then trigger the action manually

启用网络拦截打开页面,然后手动触发对应操作

opencli browser open https://example.com/target-page && opencli browser state
opencli browser open https://example.com/target-page && opencli browser state

Interact to trigger API calls

交互触发API调用

opencli browser click <N> && opencli browser network
opencli browser click <N> && opencli browser network

Inspect specific API response

查看具体API的响应内容

opencli browser network --detail <index>
undefined
opencli browser network --detail <index>
undefined

Step 4: Patch the Adapter

步骤4:补丁修复适配器

Read the adapter source file at the path from
RepairContext.adapter.sourcePath
and make targeted fixes. This path is authoritative — it may be in the repo (
clis/
) or user-local (
~/.opencli/clis/
).
bash
undefined
读取
RepairContext.adapter.sourcePath
路径下的适配器源码文件,进行针对性修复。该路径是官方权威路径,可能位于代码仓库(
clis/
)或用户本地路径(
~/.opencli/clis/
)。
bash
undefined

Read the adapter (use the exact path from diagnostic)

读取适配器代码(使用诊断数据中返回的 exact路径)

cat <RepairContext.adapter.sourcePath>
undefined
cat <RepairContext.adapter.sourcePath>
undefined

Common Fixes

常见修复场景

Selector update:
typescript
// Before: page.evaluate('document.querySelector(".old-class")...')
// After:  page.evaluate('document.querySelector(".new-class")...')
API endpoint change:
typescript
// Before: const resp = await page.evaluate(`fetch('/api/v1/old-endpoint')...`)
// After:  const resp = await page.evaluate(`fetch('/api/v2/new-endpoint')...`)
Response schema change:
typescript
// Before: const items = data.results
// After:  const items = data.data.items  // API now nests under "data"
Wait condition update:
typescript
// Before: await page.waitForSelector('.loading-spinner', { hidden: true })
// After:  await page.waitForSelector('[data-loaded="true"]')
选择器更新:
typescript
// Before: page.evaluate('document.querySelector(".old-class")...')
// After:  page.evaluate('document.querySelector(".new-class")...')
API接口地址变更:
typescript
// Before: const resp = await page.evaluate(`fetch('/api/v1/old-endpoint')...`)
// After:  const resp = await page.evaluate(`fetch('/api/v2/new-endpoint')...`)
响应结构变更:
typescript
// Before: const items = data.results
// After:  const items = data.data.items  // API现在将数据嵌套在"data"字段下
等待条件更新:
typescript
// Before: await page.waitForSelector('.loading-spinner', { hidden: true })
// After:  await page.waitForSelector('[data-loaded="true"]')

Rules for Patching

补丁修复规则

  1. Make minimal changes — fix only what's broken, don't refactor
  2. Keep the same output structure
    columns
    and return format must stay compatible
  3. Prefer API over DOM scraping — if you discover a JSON API during exploration, switch to it
  4. Use
    @jackwener/opencli/*
    imports only
    — never add third-party package imports
  5. Test after patching — run the command again to verify
  1. 最小变更原则——仅修复损坏的部分,不要重构代码
  2. 保持输出结构不变——
    columns
    和返回格式必须保持兼容
  3. 优先使用API而非DOM爬取——如果探查过程中发现了JSON API,切换为API调用方式
  4. 仅允许使用
    @jackwener/opencli/*
    导入
    ——禁止添加第三方包依赖
  5. 补丁后必须测试——重新运行命令验证修复效果

Step 5: Verify the Fix

步骤5:验证修复效果

bash
undefined
bash
undefined

Run the command normally (without diagnostic mode)

正常运行命令(不启用诊断模式)

opencli <site> <command> [args...]

If it still fails, go back to Step 1 and collect fresh diagnostics. You have a budget of **3 repair rounds** (diagnose → fix → retry). If the same error persists after a fix, try a different approach. After 3 rounds, stop and report what was tried.
opencli <site> <command> [args...]

如果仍然失败,回到步骤1重新收集最新的诊断数据。你最多有**3轮修复额度**(诊断→修复→重试)。如果修复后仍然出现相同错误,尝试其他修复方案。3轮后仍未解决,停止操作并告知用户已尝试的方案。

When to Stop

何时停止修复

Hard stops (do not modify code):
  • AUTH_REQUIRED / BROWSER_CONNECT — environment issue, not adapter bug
  • Site requires CAPTCHA — can't automate this
  • Rate limited / IP blocked — not an adapter issue
Soft stops (report after attempting):
  • 3 repair rounds exhausted — stop, report what was tried and what failed
  • Feature completely removed — the data no longer exists
  • Major redesign — needs full adapter rewrite via
    opencli-explorer
    skill
In all stop cases, clearly communicate the situation to the user rather than making futile patches.
强制停止(禁止修改代码):
  • AUTH_REQUIRED / BROWSER_CONNECT——环境问题,不是适配器bug
  • 网站需要CAPTCHA验证——无法自动化处理
  • 被限流/IP封禁——不属于适配器问题
软停止(尝试后告知用户):
  • 3轮修复额度已用尽——停止,告知用户已尝试的方案和失败原因
  • 功能已被完全移除——对应数据已不存在
  • 网站大幅改版——需要通过
    opencli-explorer
    技能完整重写适配器
所有停止场景下,都需要清晰告知用户当前情况,不要做无效的补丁修改。

Example Repair Session

修复会话示例

1. User runs: opencli zhihu hot
   → Fails: SELECTOR "Could not find element: .HotList-item"

2. AI runs: OPENCLI_DIAGNOSTIC=1 opencli zhihu hot 2>diag.json
   → Gets RepairContext with DOM snapshot showing page loaded

3. AI reads diagnostic: snapshot shows the page loaded but uses ".HotItem" instead of ".HotList-item"

4. AI explores: opencli browser open https://www.zhihu.com/hot && opencli browser state
   → Confirms new class name ".HotItem" with child ".HotItem-content"

5. AI patches: Edit adapter at RepairContext.adapter.sourcePath — replace ".HotList-item" with ".HotItem"

6. AI verifies: opencli zhihu hot
   → Success: returns hot topics
1. 用户运行: opencli zhihu hot
   → 失败: SELECTOR "Could not find element: .HotList-item"

2. AI运行: OPENCLI_DIAGNOSTIC=1 opencli zhihu hot 2>diag.json
   → 获取RepairContext,其中DOM快照显示页面已正常加载

3. AI读取诊断数据: 快照显示页面已加载,但使用的类名是".HotItem"而非".HotList-item"

4. AI探查: opencli browser open https://www.zhihu.com/hot && opencli browser state
   → 确认新的类名为".HotItem",子元素为".HotItem-content"

5. AI打补丁: 编辑`RepairContext.adapter.sourcePath`路径下的适配器,将".HotList-item"替换为".HotItem"

6. AI验证: opencli zhihu hot
   → 成功: 返回热榜话题