- Remove IdleManager and 4-hour idle auto-exit
- Daemon now stays alive until explicit shutdown or uninstall
- Add preuninstall hook for best-effort daemon cleanup on npm uninstall
- Update docs to reflect persistent daemon model
* refactor: unify browser error classification and deduplicate retry logic
Replace two overlapping error classification systems with a single
classifyBrowserError() that returns retry advice (retryable + delayMs):
- Extension/daemon transient errors → retryable, 1500ms delay
- CDP target navigation errors → retryable, 200ms delay
- Non-transient errors → not retryable
Deduplicate sendCommand/sendCommandFull retry loop into sendCommandRaw,
making both public functions thin return-value wrappers.
* fix: add error kind to prevent page-level retry of extension errors
classifyBrowserError() now returns a `kind` field:
- extension-transient: retried by daemon-client only
- target-navigation: retried by page-level settle logic
- non-retryable: no retry
Page.goto() and Page.evaluate() now only settle-retry on
target-navigation, preventing extension/daemon errors from being
silently swallowed as settle noise.
Use Chrome CDP targetId (UUID) as the canonical page identity across
all layers (extension → daemon → CLI), demoting tabId to an
extension-internal routing detail.
- Add extension/src/identity.ts: bidirectional targetId ↔ tabId mapping
with lazy refresh via chrome.debugger.getTargets()
- Update protocol: Command.page and Result.page carry targetId
- Update background.ts: resolveCommandTabId() and pageScopedResult()
helpers; all page-scoped handlers return targetId
- Add sendCommandFull() to daemon-client for responses with page identity
- Update Page class: _page stores targetId, goto/selectTab extract it
- Update record.ts: injectedPages tracks by targetId
- Add extension tests to vitest config and CI test scripts
Synced all desktop adapter command lists in desktop.md with
the actual `opencli <adapter> --help` output:
- cursor: remove non-existent status/new/dump/screenshot; add composer
- codex: remove non-existent status/new/dump/screenshot
- chatgpt: add missing model command
- chatwise: remove non-existent new/screenshot
- notion: update descriptions to match help text
- discord-app: update descriptions to match help text
- doubao-app: reorder to match help output
- antigravity: remove non-existent ask; add serve/status
Also moved `status` to the top of each adapter section where it exists.
* perf: fast-path completion, version, and shell scripts to bypass full discovery
Lightweight commands (--get-completions, --version, completion <shell>) now
resolve before any heavy module loading. Key changes:
- New completion-fast.ts: manifest-based completion + shell script generators
with zero dependency on registry/discovery/cli modules
- main.ts: static imports replaced with dynamic import() for the full startup
path so the fast path never pays the cost of loading discovery, registry,
Commander, hooks, etc.
- USER_CLIS_DIR inlined to avoid importing the entire discovery module
- completion.ts: removed manifest functions (moved to completion-fast.ts),
now only used as fallback when manifest is unavailable
* fix: address review blockers from codex-mini0
1. --version fast path: only match when argv[0] is --version/-V,
not anywhere in argv. Prevents intercepting `opencli gh --version`
which should pass through to the subcommand.
2. Completion fast path: require ALL manifests to exist (hasAllManifests),
not just one. If user clis dir exists but has no manifest, fall back
to full discovery so user adapters aren't silently dropped.
If user clis dir doesn't exist at all, skip its manifest requirement
since there are no user adapters to miss.
EMPTY_RESULT and structurally-valid SELECTOR failures are often not
adapter bugs — they're the platform shaping results under anti-scrape,
or a soft 404, or a legitimately empty search. Patching a working
adapter to chase a zero-result query breaks the next working path.
Add a pre-check section at the top of opencli-autofix listing four
rule-outs that must fail before a repair round is justified:
1. Retry with an alternative query / entry point
2. Spot-check the page in a normal Chrome tab
3. Look for soft 404s (200 with empty payload)
4. Remember that "0 results" from a search is a valid answer
Placed directly before "Step 1: Collect Diagnostic Context" so the
check runs at exactly the moment the agent would otherwise commit to
a repair round.
Audience/timing is the whole point: the skill is loaded precisely when
an error has occurred and the agent is deciding whether to repair, and
the pre-check intercepts that decision before it locks in.
11 lines of markdown, zero code, single file.
---
Inspired by https://github.com/eze-is/web-access by 一泽 Eze (MIT),
specifically the "平台返回的'内容不存在'不一定反映真实状态" mental model
from its SKILL.md. Adapted into concrete, actionable checks for
opencli's EMPTY_RESULT classification.
Note: an earlier version of this PR also added a tool-selection
decision table and a subagent-verb rule to opencli-usage. Both were
removed after review because opencli-usage only loads *after* an agent
has committed to using opencli — advice placed there arrives too late
to change tool selection, and is not seen by the main agent at
delegation time. The insights are still valid; they just don't have a
load-time match in the current skill system. This PR keeps only the
change where audience and timing actually line up.
* refactor(skills): unify command reference by site instead of technology
- Merge Browser-based and Public API sections into single alphabetical
table with type emoji tags (🌐/✅/🖥️/🔧)
- Delete browser.md and public-api.md (replaced by unified SKILL.md table)
- Add GitHub/DevOps and collaboration rows to capability lookup
- Remove stale File column from capability table
* feat(skills): add commands.md with merged examples + 8 missing adapters
- Create commands.md: merge browser.md + public-api.md into single
alphabetical-by-site reference with detailed usage examples
- Add 8 missing adapters: 1688, hupu, jianyu, lesswrong, quark,
xianyu, xiaoe, yuanbao
- Bump skill version 1.6.3 → 1.6.9 to match package.json
- Add dedicated External CLI section listing all 7 registered CLIs
(gh, obsidian, docker, lark-cli, dws, wecom-cli, vercel)
- Include install/register commands so AI agents know how to manage them
- Move gh from Desktop to External CLI section
- Update desktop.md to remove gh and reference External CLI section
* refactor(skills): merge opencli-generate into opencli-explorer
opencli-generate was a thin wrapper over generateVerifiedFromUrl,
essentially an internal pipeline orchestration. Merge its entry point
into opencli-explorer as the automated fast path, keeping one unified
skill for adapter creation.
- Delete skills/opencli-generate/SKILL.md
- Add automated generation tip to opencli-explorer SKILL.md
- Update README/README.zh-CN skill references
- Update skill-generate.ts comment
* fix(docs): fix dead link in yaml-adapter deprecation page
Change ../../CONTRIBUTING.md to ./contributing (VitePress internal link).
* refactor: remove version field from GenerateOutcome and EarlyHint
All consumers are in the same repo and evolve together — version field
adds ceremony without practical value at this stage.
Keeps schema_version in VerifiedArtifactMetadata (sidecar file format).
* refactor: migrate all 123 CLI adapters from YAML to TypeScript
Remove YAML as an adapter format entirely. All adapters now use
TypeScript with cli() from @jackwener/opencli/registry.
- Convert 123 YAML adapter files to TypeScript via batch script
- Remove YAML scanning from discovery.ts (registerYamlCli, yaml import)
- Remove scanYaml() and shouldReplaceManifestEntry() from build-manifest.ts
- Change synthesize.ts to output JSON candidates (internal format)
- Change generate-verified.ts to write .ts adapter files instead of .yaml
- Delete yaml-schema.ts (dead code) and scripts/yaml-to-ts.mjs (one-time tool)
- Update all tests to match new format
Closes discussion in #OpenCLI thread 47ddba82.
* fix: close YAML migration gaps in plugin scaffold, validation, and scan
- plugin-scaffold.ts: generate hello.ts (TS pipeline) instead of hello.yaml
- plugin.ts validatePluginStructure: no longer accept .yaml as valid command file
- plugin.ts scanPluginCommands: remove .yaml/.yml from scanned extensions
- discovery.ts: add explicit log.warn() when YAML files detected in clis/ or plugins/
- plugin.test.ts: update all test fixtures from .yaml to .js
- plugin-scaffold.test.ts: update hello.yaml references to hello.ts
- Delete dead src/yaml-schema.ts
Resolves PR #887 review blockers from @mbp-codex-pr0.
* refactor: complete YAML removal across docs, skills, record, and binance adapters
Code changes:
- record.ts: candidate output changed from .yaml (yaml.dump) to .json (JSON.stringify), removed js-yaml import
- src/clis/binance: convert all 11 YAML adapters to TypeScript cli() format
- binance/commands.test.ts: rewrite to use registry instead of yaml.load
- skill-generate.test.ts, diagnostic.test.ts: update mock paths from .yaml to .ts
- build-manifest.ts, synthesize.ts: update stale YAML comments
Documentation:
- README.md: remove .yaml from Dynamic Loader, fix plugin types, fix synthesize comment
- README.zh-CN.md: fix synthesize comment
- CONTRIBUTING.md: replace YAML Adapter section with Pipeline Adapter (TS), update arg examples
- docs/developer/yaml-adapter.md: replaced with deprecation redirect
- docs/developer/architecture.md: remove YAML pipeline references
- docs/developer/contributing.md: remove YAML adapter section
- docs/developer/ai-workflow.md: YAML → TS in synthesize description
- docs/guide/getting-started.md: remove .yaml from loader, update engine description
- docs/guide/plugins.md: remove YAML plugin option, update plugin types
- docs/index.md, docs/comparison.md: remove YAML adapter references
- docs/zh/guide/plugins.md: remove .yaml from scan description
Skills:
- opencli-explorer/SKILL.md: rewrite YAML vs TS decision tree to TS-only
- opencli-oneshot/SKILL.md: replace YAML templates with TS cli() templates
- opencli-generate/SKILL.md: YAML artifact path → TS artifact path
- opencli-usage/SKILL.md, plugins.md: update adapter format references
* fix: clean up remaining YAML adapter references in docs
- docs/zh/guide/plugins.md: replace YAML plugin example with TS pipeline
- docs/developer/testing.md: YAML Adapter heading → Adapter, remove validate line
- TESTING.md: same fix in root testing doc
- CONTRIBUTING.md: remove "YAML validation" comment
- docs/.vitepress/config.mts: mark YAML Adapter Guide as (Deprecated) in nav
- docs/advanced/download.md: remove "YAML Adapters" from pipeline step heading
All consumers are in the same repo and evolve together — version field
adds ceremony without practical value at this stage.
Keeps schema_version in VerifiedArtifactMetadata (sidecar file format).
* fix: use Strategy.PUBLIC enum in skill-generate test to fix typecheck regression
* feat: add P2 EarlyHint callback channel to generateVerifiedFromUrl
Add optional onEarlyHint callback for internal cost gating before verify stage.
- EarlyHint type: version, stage, continue, reason, confidence, candidate?
- 3 emit points: explore (viable/not), synthesize (candidate/not), cascade (auth/ok)
- candidate only on synthesize/cascade + continue:true (not on stop or explore)
- unsupported-required-args goes directly to P1 terminal, no P2 hint emitted
- 6 new tests covering all hint paths + guardrails
* docs: add opencli-generate skill spec (SKILL.md)
Captures A+B consensus from team discussion:
- Input: url + goal? (natural language intent hint)
- Output: SkillOutput with machine-readable fields + human message
- Decision tree: thin mapping from GenerateOutcome
- Guardrails: no re-orchestration, no auto-escalation, no new taxonomy
- P1/P2 boundary: P1 is single source of truth, P2 transparent to skill
* fix: address review nits on skill spec
- Make path explicitly optional in needs-human-check decision tree
- Add missing non-array-result message template
* feat: add GenerateOutcome → SkillOutput thin wrapper
Implements the skill mapping layer per opencli-generate SKILL.md:
- mapOutcomeToSkillOutput: thin translation from P1 contract to agent-facing output
- executeGenerateSkill: entry point accepting SkillInput (url + goal?)
- Message templates for all StopReason and EscalationReason values
- 8 tests covering all outcome paths and contract shape validation
* fix: prefer outcome.message for richer context in needs-human-check
When GenerateOutcome has a message (e.g. "required args: id"), use it
instead of the generic template, so the specific args info reaches the user.
All 68 browser adapter links and 8 desktop adapter links in
docs/adapters/index.md were missing the .md file extension,
causing broken links when navigating the documentation on GitHub.
- Add getDaemonHealth() returning 'stopped' | 'no-extension' | 'ready'
- Delete discover.ts (thin wrapper with no value)
- Bridge uses getDaemonHealth() + _pollUntilReady() (eliminates duplicate polling)
- Doctor simplified: live check auto-starts daemon; no-live mode does minimal
auto-start only when stopped (avoids misreporting idle-exit as failure)
- CommanderAdapter preserves error message/hint detail (not just generic title)
- All callers use single unified status entry point
* fix(xiaohongshu): scope note interaction selectors to .interact-container
The .like-wrapper / .collect-wrapper / .chat-wrapper class names are
also used by every comment's like/reply buttons in the comment section.
querySelector returned the FIRST match — which on a note with comments
is a comment's count, not the post's. As a result, `xiaohongshu note`
returned wrong like/collect/comment counts for any note that had user
comments.
Scoping each selector to .interact-container (the post's main
interaction bar) returns the correct post-level counts.
Verified on multiple notes:
- Note A: was returning likes=2, now correctly returns likes=74
- Note B: was returning likes=1, now correctly returns likes=796
- Note C: was returning likes=1, now correctly returns likes=269
* test(xiaohongshu): add regression check for .interact-container selector scope
Verify the evaluate script passes scoped selectors so unscoped
versions can't silently regress. Follows reviewer suggestion to
assert on page.evaluate.mock.calls[0][0].
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: add GitHub Trending, Binance, and Weather (Open Meteo) adapters
GitHub Trending (2 commands, browser mode):
- repos: trending repositories with stars, forks, language filter
- developers: trending developers with popular repos
Supports --since daily/weekly/monthly and --language filter
Binance (11 commands, public API via data-api.binance.vision):
- top: top trading pairs by 24h volume
- price: single pair 24h price stats
- prices: latest prices for all pairs
- ticker: 24h ticker statistics
- gainers: top gaining pairs by 24h change
- losers: top losing pairs by 24h change
- trades: recent trades for a pair
- depth: order book bid prices
- asks: order book ask prices
- klines: candlestick/kline data
- pairs: list active trading pairs
Weather / Open Meteo (11 commands, free public API, no key needed):
- current: current weather for a city
- forecast: daily forecast up to 16 days
- hourly: hourly forecast
- search: city geocoding lookup
- air: air quality index (simple)
- air-quality: detailed air quality (US/EU AQI, PM2.5, PM10, ozone, NO2, SO2)
- sunrise: sunrise/sunset times with UV index
- wind: detailed wind forecast with gusts and 80m altitude
- precipitation: rain/snow forecast with probability
- history: historical weather up to 92 past days
- compare: side-by-side weather comparison across cities
All 24 commands tested with live data. 258 existing tests pass.
* docs: add missing douban, sinablog, substack adapter documentation
* fix(binance): sort numeric metrics and filter active pairs
* chore: drop non-binance adapters from pr214
* chore: drop binance docs from pr214
---------
Co-authored-by: jackwener <jakevingoo@gmail.com>
* feat: add Self-Repair protocol for automatic adapter fixing
When an AI agent uses opencli and a command fails, the agent
automatically diagnoses the failure, fixes the adapter, and retries.
- Add CLAUDE.md with Self-Repair protocol (auto-loaded by Claude Code)
- Add designs/self-repair-protocol.md documenting the approach
- Update opencli-repair skill: add Safety Boundaries (AUTH/BROWSER → STOP,
sourcePath-only scope, max 3 rounds), fix AUTH_REQUIRED guidance
- Update opencli-usage skill: add Self-Repair section
Key design decisions:
- Repair target is always RepairContext.adapter.sourcePath (works for both
repo-local clis/ and user-local ~/.opencli/clis/)
- Only adapter files may be modified, never core src/
- Max 3 repair rounds per failure
- AUTH_REQUIRED and BROWSER_CONNECT are hard stops (report, don't modify)
* fix: align auth boundary and scope language across all documents
- Remove "Auth changed (AUTH_REQUIRED)" exploration section from
opencli-repair skill — contradicted the hard stop rule above it
- Update design doc: scope language matches repo-local + explicit skill
delivery model, not universal product behavior
- Update usage skill: reference sourcePath instead of "files under clis/"
* fix: replace remaining repo-relative clis/ paths with sourcePath in design doc
* refactor: rename opencli-repair to opencli-autofix, remove CLAUDE.md
CLAUDE.md was wrong — users don't work inside the opencli repo, and
the protocol shouldn't assume Claude Code. The skill is the portable
delivery mechanism for any AI agent.
- Rename skills/opencli-repair → skills/opencli-autofix
- Remove CLAUDE.md (not the right delivery mechanism)
- Update all references in usage skill and design doc
- Design doc rewritten to reflect skill-first approach
* fix: use sourcePath in example repair session
* feat: emit AutoFix hint on repairable adapter errors
When a command fails with a repairable error (SELECTOR, EMPTY_RESULT,
COMMAND_EXEC, or generic http/not-found), the error output now includes
a hint telling agents to re-run with OPENCLI_DIAGNOSTIC=1 for repair
context. This is the trigger mechanism that bridges the gap between
"command failed" and "agent enters autofix loop".
Non-repairable errors (AUTH_REQUIRED, BROWSER_CONNECT, ARGUMENT) do not
emit the hint — these require user action, not adapter fixes.
* fix: narrow AutoFix hint to adapter-drift errors only
Remove hint from CommandExecutionError (covers env/launcher/runtime
issues, not adapter drift) and generic http errors (often temporary
site issues). Keep hint only for SelectorError, EmptyResultError,
and generic not-found — clear adapter-drift signals.
When the Browser Bridge extension is older than the CLI, sending
'network-capture-start' to the daemon returns 'Unknown action',
causing explore and operate-open to crash with an unhandled error.
Wrap startNetworkCapture calls with .catch() so they degrade
gracefully — explore continues without network capture data, and
operate-open falls back to the JS interceptor injection.
The compose page needs to load Draft.js editor which is heavier than
primaryColumn. 8s is too tight for slow networks and will cause flaky
failures. 15s aligns with the file input timeout (20s) in magnitude.