| name | opencli |
| description | OpenCLI — Make any website or Electron App your CLI. Zero risk, AI-powered, reuse Chrome login. 80+ commands across 19 sites. |
| version | 0.7.4 |
| author | jackwener |
| tags | ["cli","browser","web","chrome-extension","cdp","bilibili","zhihu","twitter","github","v2ex","hackernews","reddit","xiaohongshu","xueqiu","youtube","boss","coupang","AI","agent"] |
OpenCLI
Make any website or Electron App your CLI. Reuse Chrome login, zero risk, AI-powered discovery.
[!CAUTION]
AI Agent 必读:创建或修改任何适配器之前,你必须先阅读 CLI-EXPLORER.md!
该文档包含完整的 API 发现工作流(必须使用浏览器探索)、5 级认证策略决策树、平台 SDK 速查表、tap 步骤调试流程、分页 API 模板、级联请求模式、以及常见陷阱。
本文件(SKILL.md)仅提供命令参考和简化模板,不足以正确开发适配器。
Install & Run
npm install -g @jackwener/opencli
opencli <command>
cd ~/code/opencli && npm install
npx tsx src/main.ts <command>
npm update -g @jackwener/opencli
Prerequisites
Browser commands require:
- Chrome browser running (logged into target sites)
- opencli Browser Bridge Chrome extension installed (load
extension/ as unpacked in chrome://extensions)
- No further setup needed — the daemon auto-starts on first browser command
Note: You must be logged into the target website in Chrome before running commands. Tabs opened during command execution are auto-closed afterwards.
Public API commands (hackernews, github search, v2ex) need no browser.
Commands Reference
Data Commands
opencli bilibili hot --limit 10
opencli bilibili search --keyword "rust"
opencli bilibili me
opencli bilibili favorite
opencli bilibili history --limit 20
opencli bilibili feed --limit 10
opencli bilibili user-videos --uid 12345
opencli bilibili subtitle --bvid BV1xxx
opencli bilibili dynamic --limit 10
opencli bilibili ranking --limit 10
opencli bilibili following --limit 20
opencli zhihu hot --limit 10
opencli zhihu search --keyword "AI"
opencli zhihu question --id 34816524
opencli xiaohongshu search --keyword "美食"
opencli xiaohongshu notifications
opencli xiaohongshu feed --limit 10
opencli xiaohongshu me
opencli xiaohongshu user --uid xxx
opencli xueqiu hot-stock --limit 10
opencli xueqiu stock --symbol SH600519
opencli xueqiu watchlist
opencli xueqiu feed
opencli xueqiu hot --limit 10
opencli xueqiu search --keyword "特斯拉"
opencli github search --keyword "cli"
opencli twitter trending --limit 10
opencli twitter bookmarks --limit 20
opencli twitter search --keyword "AI"
opencli twitter profile elonmusk
opencli twitter timeline --limit 20
opencli twitter thread 1234567890
opencli twitter article 1891511252174299446
opencli twitter follow elonmusk
opencli twitter unfollow elonmusk
opencli twitter bookmark https://x.com/...
opencli twitter unbookmark https://x.com/...
opencli reddit hot --limit 10
opencli reddit hot --subreddit programming
opencli reddit frontpage --limit 10
opencli reddit popular --limit 10
opencli reddit search --query "AI" --sort top --time week
opencli reddit subreddit --name rust --sort top --time month
opencli reddit read --post_id 1abc123
opencli reddit user --username spez
opencli reddit user-posts --username spez
opencli reddit user-comments --username spez
opencli reddit upvote --post_id xxx --direction up
opencli reddit save --post_id xxx
opencli reddit comment --post_id xxx --text "Great!"
opencli reddit subscribe --subreddit python
opencli reddit saved --limit 10
opencli reddit upvoted --limit 10
opencli v2ex hot --limit 10
opencli v2ex latest --limit 10
opencli v2ex topic --id 1024
opencli v2ex daily
opencli v2ex me
opencli v2ex notifications --limit 10
opencli hackernews top --limit 10
opencli bbc news --limit 10
opencli weibo hot --limit 10
opencli boss search --query "AI agent"
opencli boss detail --securityId xxx
opencli youtube search --query "rust"
opencli youtube video --url "https://www.youtube.com/watch?v=xxx"
opencli youtube transcript --url "https://www.youtube.com/watch?v=xxx"
opencli youtube transcript --url "xxx" --lang zh-Hans --mode raw
opencli yahoo-finance quote --symbol AAPL
opencli sinafinance news --limit 10 --type 1
opencli reuters search --query "AI"
opencli smzdm search --keyword "耳机"
opencli ctrip search --query "三亚"
opencli antigravity status
opencli antigravity send "hello"
opencli antigravity read
opencli antigravity new
opencli antigravity extract-code
opencli antigravity model claude
opencli antigravity watch
Management Commands
opencli list
opencli list --json
opencli list -f yaml
opencli validate
opencli validate bilibili
opencli setup
opencli doctor
opencli doctor --live
AI Agent Workflow
opencli explore <url> --site <name>
opencli synthesize <site>
opencli generate <url> --goal "hot"
opencli cascade <api-url>
opencli explore <url> --auto --click "字幕,CC,评论"
opencli verify
Output Formats
All built-in commands support --format / -f with table, json, yaml, md, and csv.
The list command supports the same formats and also keeps --json as a compatibility alias.
opencli list -f yaml
opencli bilibili hot -f table
opencli bilibili hot -f json
opencli bilibili hot -f yaml
opencli bilibili hot -f md
opencli bilibili hot -f csv
Verbose Mode
opencli bilibili hot -v
Creating Adapters
[!TIP]
快速模式:如果你只想为一个具体页面生成一个命令,直接看 CLI-ONESHOT.md。
只需要一个 URL + 一句话描述,4 步搞定。
[!IMPORTANT]
完整模式 — 在写任何代码之前,先阅读 CLI-EXPLORER.md。
它包含:① AI Agent 浏览器探索工作流 ② 认证策略决策树 ③ 平台 SDK(如 Bilibili 的 apiGet/fetchJson)④ YAML vs TS 选择指南 ⑤ tap 步骤调试方法 ⑥ 级联请求模板 ⑦ 常见陷阱表。
下方仅为简化模板参考,直接使用极易踩坑。
YAML Pipeline (declarative, recommended)
Create src/clis/<site>/<name>.yaml:
site: mysite
name: hot
description: Hot topics
domain: www.mysite.com
strategy: cookie
browser: true
args:
limit:
type: int
default: 20
description: Number of items
pipeline:
- navigate: https://www.mysite.com
- evaluate: |
(async () => {
const res = await fetch('/api/hot', { credentials: 'include' });
const d = await res.json();
return d.data.items.map(item => ({
title: item.title,
score: item.score,
}));
})()
- map:
rank: ${{ index + 1 }}
title: ${{ item.title }}
score: ${{ item.score }}
- limit: ${{ args.limit }}
columns: [rank, title, score]
For public APIs (no browser):
strategy: public
browser: false
pipeline:
- fetch:
url: https://api.example.com/hot.json
- select: data.items
- map:
title: ${{ item.title }}
- limit: ${{ args.limit }}
TypeScript Adapter (programmatic)
Create src/clis/<site>/<name>.ts. It will be automatically dynamically loaded (DO NOT manually import it in index.ts):
import { cli, Strategy } from '../../registry.js';
cli({
site: 'mysite',
name: 'search',
strategy: Strategy.INTERCEPT,
args: [{ name: 'keyword', required: true }],
columns: ['rank', 'title', 'url'],
func: async (page, kwargs) => {
await page.goto('https://www.mysite.com/search');
await page.installInterceptor('/api/search');
await page.autoScroll({ times: 3, delayMs: 2000 });
const requests = await page.getInterceptedRequests();
let results = [];
for (const req of requests) {
results.push(...req.data.items);
}
return results.map((item, i) => ({
rank: i + 1, title: item.title, url: item.url,
}));
},
});
When to use TS: XHR interception (page.installInterceptor), infinite scrolling (page.autoScroll), cookie extraction, complex data transforms (like GraphQL unwrapping).
Pipeline Steps
| Step | Description | Example |
|---|
navigate | Go to URL | navigate: https://example.com |
fetch | HTTP request (browser cookies) | fetch: { url: "...", params: { q: "..." } } |
evaluate | Run JavaScript in page | evaluate: | (async () => { ... })() |
select | Extract JSON path | select: data.items |
map | Map fields | map: { title: "${{ item.title }}" } |
filter | Filter items | filter: item.score > 100 |
sort | Sort items | sort: { by: score, order: desc } |
limit | Cap result count | limit: ${{ args.limit }} |
intercept | Declarative XHR capture | intercept: { trigger: "navigate:...", capture: "api/hot" } |
tap | Store action + XHR capture | tap: { store: "feed", action: "fetchFeeds", capture: "homefeed" } |
snapshot | Page accessibility tree | snapshot: { interactive: true } |
click | Click element | click: ${{ ref }} |
type | Type text | type: { ref: "@1", text: "hello" } |
wait | Wait for time/text | wait: 2 or wait: { text: "loaded" } |
press | Press key | press: Enter |
Template Syntax
${{ args.keyword }}
${{ args.limit | default(20) }}
${{ item.title }}
${{ item.data.nested.field }}
${{ index }}
${{ index + 1 }}
5-Tier Authentication Strategy
| Tier | Name | Method | Example |
|---|
| 1 | public | No auth, Node.js fetch | Hacker News, V2EX |
| 2 | cookie | Browser fetch with credentials: include | Bilibili, Zhihu |
| 3 | header | Custom headers (ct0, Bearer) | Twitter GraphQL |
| 4 | intercept | XHR interception + store mutation | 小红书 Pinia |
| 5 | ui | Full UI automation (click/type/scroll) | Last resort |
Environment Variables
| Variable | Default | Description |
|---|
OPENCLI_DAEMON_PORT | 19825 | Daemon listen port |
OPENCLI_BROWSER_CONNECT_TIMEOUT | 30 | Browser connection timeout (sec) |
OPENCLI_BROWSER_COMMAND_TIMEOUT | 45 | Command execution timeout (sec) |
OPENCLI_BROWSER_EXPLORE_TIMEOUT | 120 | Explore timeout (sec) |
OPENCLI_VERBOSE | — | Show daemon/extension logs |
Troubleshooting
| Issue | Solution |
|---|
npx not found | Install Node.js: brew install node |
Extension not connected | 1) Chrome must be open 2) Install opencli Browser Bridge extension |
Target page context error | Add navigate: step before evaluate: in YAML |
| Empty table data | Check if evaluate returns correct data path |
| Daemon issues | curl localhost:19825/status to check, curl localhost:19825/logs for extension logs |