OpenCLI AutoFix — Automatic Adapter Self-Repair
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.
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 limiting
—
STOP.
Not an adapter issue.
Scope constraint:
Only modify the file at
RepairContext.adapter.sourcePath
— this is the authoritative adapter location (may be
clis/
Verify extension + daemon connectivity
When to Use This Skill
Use when
opencli
< command
[ args .. . ] 2
diagnostic.json This outputs a RepairContext JSON between OPENCLIDIAGNOSTIC_ 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.js" , "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 '/OPENCLIDIAGNOSTIC_/{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 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 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 browser 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 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
API changed (API_ERROR, EMPTY_RESULT)
Open page with network interceptor, then trigger the action manually
opencli browser open https://example.com/target-page && opencli browser state
Interact to trigger API calls
opencli browser click < N
&& opencli browser network
Inspect specific API response
opencli browser network --detail < index
Step 4: Patch the Adapter 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/ ).
Read the adapter (use the exact path from diagnostic)
cat < RepairContext.adapter.sourcePath
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 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. Step 6: File an Upstream Issue If the retry passes , the local adapter has drifted from upstream. File a GitHub issue so the fix flows back to jackwener/OpenCLI . Do NOT file for: AUTH_REQUIRED , BROWSER_CONNECT , ARGUMENT , CONFIG — environment/usage issues, not adapter bugs CAPTCHA or rate limiting — not fixable upstream Failures you couldn't actually fix (3 rounds exhausted) Only file after a verified local fix — the retry must pass first. Procedure: Prepare the issue content from the RepairContext you already have: Title: [autofix]
/ : (e.g. [autofix] zhihu/hot: SELECTOR ) Body (use this template):
Summary OpenCLI autofix repaired this adapter locally, and the retry passed.
Adapter
Site:
<site>
-
Command:
<command>
-
OpenCLI version:
<version from opencli --version>
Original failure
Error code:
<error_code>
~
~~
Local fix summary
~
~~
<1-2 sentence description of what you changed and why>
~~
~
_
Issue filed by OpenCLI autofix after a verified local repair.
_
Ask the user before filing.
Show them the draft title and body. Only proceed if they confirm.
If the user approves and
gh auth status
succeeds:
gh issue create
--repo
jackwener/OpenCLI
\
--title
"[autofix]