OpenCLI Repair — AI-Driven Adapter Self-Repair
When an adapter breaks because a website changed its DOM, API, or auth flow, use this skill to diagnose the failure and patch the adapter.
Prerequisites
opencli doctor # Verify extension + daemon connectivity
When to Use This Skill
Use when opencli <site> <command> fails with errors like:
-
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
Step 1: Collect Diagnostic Context
Run the failing command with diagnostic mode enabled:
OPENCLI_DIAGNOSTIC=1 opencli <site> <command> [args...] 2>diagnostic.json
This outputs a RepairContext JSON between OPENCLI_DIAGNOSTIC markers in stderr:
{ "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:
Extract JSON between markers from stderr output
cat diagnostic.json | sed -n '/OPENCLI_DIAGNOSTIC/{n;p;}'
Step 2: Analyze the Failure
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 Walk login flow with operate
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 source field)
-
What did the page look like when it failed? (Read the snapshot field)
-
What network requests happened? (Read networkRequests )
-
What's the gap between what the adapter expects and what the page provides?
Step 3: Explore the Current Website
Use opencli operate to inspect the live website. Never use the broken adapter — it will just fail again.
DOM changed (SELECTOR errors)
Open the page and inspect current DOM
opencli operate open https://example.com/target-page && opencli operate state
Look for elements that match the adapter's intent
Compare the snapshot with what the adapter expects
API changed (API_ERROR, EMPTY_RESULT)
Open page with network interceptor, then trigger the action manually
opencli operate open https://example.com/target-page && opencli operate state
Interact to trigger API calls
opencli operate click <N> && opencli operate network
Inspect specific API response
opencli operate network --detail <index>
Auth changed (AUTH_REQUIRED)
Check current auth state
opencli operate open https://example.com && opencli operate state
If login page: inspect the login form
opencli operate state # Look for login form fields
Step 4: Patch the Adapter
Read the adapter source file and make targeted fixes:
Read the adapter
cat <sourcePath from diagnostic>
Common Fixes
Selector update:
// Before: page.evaluate('document.querySelector(".old-class")...') // After: page.evaluate('document.querySelector(".new-class")...')
API endpoint change:
// 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:
// Before: const items = data.results // After: const items = data.data.items // API now nests under "data"
Wait condition update:
// 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 — columns and return format must stay compatible
-
Prefer API over DOM scraping — if you discover a JSON API during exploration, switch to it
-
Use @jackwener/opencli/* imports only — never add third-party package imports
-
Test after patching — run the command again to verify
Step 5: Verify the Fix
Run the command normally (without diagnostic mode)
opencli <site> <command> [args...]
If it still fails, go back to Step 3 and explore further. If the website has fundamentally changed (major redesign, removed feature), report that the adapter needs a full rewrite.
When to Give Up
Not all failures are repairable with a quick patch:
-
Site requires CAPTCHA — can't automate this
-
Feature completely removed — the data no longer exists
-
Major redesign — needs full adapter rewrite via opencli-explorer skill
-
Rate limited / IP blocked — not an adapter issue
In these cases, clearly communicate the situation to the user rather than making futile patches.
Example Repair Session
-
User runs: opencli zhihu hot → Fails: SELECTOR "Could not find element: .HotList-item"
-
AI runs: OPENCLI_DIAGNOSTIC=1 opencli zhihu hot 2>diag.json → Gets RepairContext with DOM snapshot showing page loaded
-
AI reads diagnostic: snapshot shows the page loaded but uses ".HotItem" instead of ".HotList-item"
-
AI explores: opencli operate open https://www.zhihu.com/hot && opencli operate state → Confirms new class name ".HotItem" with child ".HotItem-content"
-
AI patches: Edit clis/zhihu/hot.ts — replace ".HotList-item" with ".HotItem"
-
AI verifies: opencli zhihu hot → Success: returns hot topics