qiaomu-opencli-autofix
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOpenCLI AutoFix — Automatic Adapter Self-Repair
OpenCLI AutoFix — 适配器自动自修复
When an 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或响应结构而失败时,自动诊断、修复适配器并重试,而不是仅报错。
opencliSafety Boundaries
安全边界
Before starting any repair, check these hard stops:
- (exit code 77) — STOP. Do not modify code. Tell the user to log into the site in Chrome.
AUTH_REQUIRED - (exit code 69) — STOP. Do not modify code. Tell the user to run
BROWSER_CONNECT.opencli doctor - CAPTCHA / rate limiting — STOP. Not an adapter issue.
Scope constraint:
- Only modify the file at — this is the authoritative adapter location (may be
RepairContext.adapter.sourcePathin repo orclis/<site>/for npm installs)~/.opencli/clis/<site>/ - Never modify ,
src/,extension/,tests/, orpackage.jsontsconfig.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.
启动任何修复操作前,请先检查以下强制停止规则:
- (退出码 77)——立即停止,不要修改代码,告知用户需要在Chrome中登录对应网站。
AUTH_REQUIRED - (退出码 69)——立即停止,不要修改代码,告知用户运行
BROWSER_CONNECT命令。opencli doctor - CAPTCHA / 限流——立即停止,不属于适配器问题。
范围限制:
- 仅允许修改路径下的文件——这是官方的适配器存储路径,可能是代码仓库中的
RepairContext.adapter.sourcePath路径,也可能是npm安装对应的clis/<site>/路径~/.opencli/clis/<site>/ - 禁止修改、
src/、extension/、tests/或package.json文件tsconfig.json
重试限额:每次故障最多允许3轮修复。如果3轮“诊断→修复→重试”流程后问题仍未解决,停止操作并告知用户已尝试的方案。
Prerequisites
前置条件
bash
opencli doctor # Verify extension + daemon connectivitybash
opencli doctor # 验证扩展与守护进程的连通性When to Use This Skill
何时使用此技能
Use when fails with repairable errors:
opencli <site> <command>- 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_RESULTSELECTOR- Retry with an alternative query or entry point. If returns 0 but
opencli xiaohongshu search "X"returns 20, the adapter is fine — the platform was shaping results for the first query.opencli xiaohongshu search "X 攻略" - 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 / re-login, not editing source.
opencli doctor - 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 , that is a valid answer — report it to the user as "no matches for this query" rather than patching the adapter.
results: []
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_RESULTSELECTOR- 使用替代查询词或入口重试。如果返回0条结果,但
opencli xiaohongshu search "X"返回20条结果,说明适配器正常,只是平台对第一个查询做了结果限制。opencli xiaohongshu search "X 攻略" - 在普通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.jsonThis outputs a JSON between markers in stderr:
RepairContext___OPENCLI_DIAGNOSTIC___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该命令会在标准错误流的标记之间输出 JSON内容:
___OPENCLI_DIAGNOSTIC___RepairContextjson
{
"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
undefinedExtract JSON between markers from stderr output
从标准错误输出中提取标记之间的JSON内容
cat diagnostic.json | sed -n '/OPENCLI_DIAGNOSTIC/{n;p;}'
undefinedcat diagnostic.json | sed -n '/OPENCLI_DIAGNOSTIC/{n;p;}'
undefinedStep 2: Analyze the Failure
步骤2:分析故障原因
Read the diagnostic context and the adapter source. Classify the root cause:
| Error Code | Likely Cause | Repair Strategy |
|---|---|---|
| SELECTOR | DOM restructured, class/id renamed | Explore current DOM → find new selector |
| EMPTY_RESULT | API response schema changed, or data moved | Check network → find new response path |
| API_ERROR | Endpoint URL changed, new params required | Discover new API via network intercept |
| AUTH_REQUIRED | Login flow changed, cookies expired | STOP — tell user to log in, do not modify code |
| TIMEOUT | Page loads differently, spinner/lazy-load | Add/update wait conditions |
| PAGE_CHANGED | Major redesign | May need full adapter rewrite |
Key questions to answer:
- What is the adapter trying to do? (Read the field)
source - What did the page look like when it failed? (Read the field)
snapshot - What network requests happened? (Read )
networkRequests - What's the gap between what the adapter expects and what the page provides?
读取诊断上下文和适配器源码,归类根因:
| 错误码 | 可能原因 | 修复策略 |
|---|---|---|
| SELECTOR | DOM结构重构,class/id重命名 | 探查当前DOM → 找到新的选择器 |
| EMPTY_RESULT | API响应结构变更,或数据位置迁移 | 检查网络请求 → 找到新的响应路径 |
| API_ERROR | 接口URL变更,需要新参数 | 通过网络抓包发现新的API |
| AUTH_REQUIRED | 登录流程变更,cookie过期 | 立即停止——告知用户登录,不要修改代码 |
| TIMEOUT | 页面加载逻辑变更, spinner/懒加载逻辑变更 | 添加/更新等待条件 |
| PAGE_CHANGED | 网站大幅改版 | 可能需要完整重写适配器 |
需要明确的核心问题:
- 适配器的预期功能是什么?(读取字段)
source - 故障发生时页面的实际状态是什么?(读取字段)
snapshot - 发生了哪些网络请求?(读取字段)
networkRequests - 适配器的预期输出和页面实际提供的内容之间的差异是什么?
Step 3: Explore the Current Website
步骤3:探查当前网站状态
Use to inspect the live website. Never use the broken adapter — it will just fail again.
opencli browser使用检查实时网站状态,不要使用损坏的适配器——它只会再次失败。
opencli browserDOM changed (SELECTOR errors)
DOM变更(SELECTOR错误)
bash
undefinedbash
undefinedOpen 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
对比快照和适配器的预期结构
undefinedundefinedAPI changed (API_ERROR, EMPTY_RESULT)
API变更(API_ERROR、EMPTY_RESULT错误)
bash
undefinedbash
undefinedOpen 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>
undefinedopencli browser network --detail <index>
undefinedStep 4: Patch the Adapter
步骤4:补丁修复适配器
Read the adapter source file at the path from and make targeted fixes. This path is authoritative — it may be in the repo () or user-local ().
RepairContext.adapter.sourcePathclis/~/.opencli/clis/bash
undefined读取路径下的适配器源码文件,进行针对性修复。该路径是官方权威路径,可能位于代码仓库()或用户本地路径()。
RepairContext.adapter.sourcePathclis/~/.opencli/clis/bash
undefinedRead the adapter (use the exact path from diagnostic)
读取适配器代码(使用诊断数据中返回的 exact路径)
cat <RepairContext.adapter.sourcePath>
undefinedcat <RepairContext.adapter.sourcePath>
undefinedCommon 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
补丁修复规则
- Make minimal changes — fix only what's broken, don't refactor
- Keep the same output structure — and return format must stay compatible
columns - Prefer API over DOM scraping — if you discover a JSON API during exploration, switch to it
- Use imports only — never add third-party package imports
@jackwener/opencli/* - Test after patching — run the command again to verify
- 最小变更原则——仅修复损坏的部分,不要重构代码
- 保持输出结构不变——和返回格式必须保持兼容
columns - 优先使用API而非DOM爬取——如果探查过程中发现了JSON API,切换为API调用方式
- 仅允许使用导入——禁止添加第三方包依赖
@jackwener/opencli/* - 补丁后必须测试——重新运行命令验证修复效果
Step 5: Verify the Fix
步骤5:验证修复效果
bash
undefinedbash
undefinedRun 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 skill
opencli-explorer
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 topics1. 用户运行: 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
→ 成功: 返回热榜话题