mirror of
https://github.com/jackwener/OpenCLI.git
synced 2026-09-14 18:25:42 +08:00
docs: add VitePress documentation site (#112)
- Add VitePress with full navigation, sidebar, i18n (en/zh), local search - Create 50+ doc pages: guide, adapters (browser + desktop), developer, advanced - Migrate content from README.md, CONTRIBUTING.md, TESTING.md, CDP.md, CLI-ELECTRON.md - Migrate all 11 adapter READMEs to structured documentation - Add new pages: architecture, yaml-adapter guide, ts-adapter guide, ai-workflow - Add GitHub Actions workflow for deploying to GitHub Pages - Add Chinese locale pages (getting-started, installation, browser-bridge, etc.) - Add docs:dev, docs:build, docs:preview npm scripts
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
name: Deploy Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths: ['docs/**']
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: pages
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: npm
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build docs
|
||||
run: npm run docs:build
|
||||
|
||||
- uses: actions/configure-pages@v4
|
||||
|
||||
- uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: docs/.vitepress/dist
|
||||
|
||||
deploy:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
@@ -6,6 +6,10 @@ dist/
|
||||
.mcp.json
|
||||
*.log
|
||||
|
||||
# VitePress
|
||||
docs/.vitepress/dist
|
||||
docs/.vitepress/cache
|
||||
|
||||
# Extensions & Secrets
|
||||
*.pem
|
||||
*.crx
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
import { defineConfig } from 'vitepress'
|
||||
|
||||
export default defineConfig({
|
||||
title: 'OpenCLI',
|
||||
description: 'Make any website or Electron App your CLI — AI-powered, account-safe, self-healing.',
|
||||
|
||||
head: [
|
||||
['meta', { property: 'og:title', content: 'OpenCLI Documentation' }],
|
||||
['meta', { property: 'og:description', content: 'Make any website or Electron App your CLI.' }],
|
||||
['meta', { name: 'twitter:card', content: 'summary_large_image' }],
|
||||
],
|
||||
|
||||
locales: {
|
||||
root: {
|
||||
label: 'English',
|
||||
lang: 'en',
|
||||
themeConfig: {
|
||||
nav: [
|
||||
{ text: 'Guide', link: '/guide/getting-started' },
|
||||
{ text: 'Adapters', link: '/adapters/' },
|
||||
{ text: 'Developer', link: '/developer/contributing' },
|
||||
{ text: 'Advanced', link: '/advanced/cdp' },
|
||||
],
|
||||
sidebar: {
|
||||
'/guide/': [
|
||||
{
|
||||
text: 'Guide',
|
||||
items: [
|
||||
{ text: 'Getting Started', link: '/guide/getting-started' },
|
||||
{ text: 'Installation', link: '/guide/installation' },
|
||||
{ text: 'Browser Bridge', link: '/guide/browser-bridge' },
|
||||
{ text: 'Troubleshooting', link: '/guide/troubleshooting' },
|
||||
],
|
||||
},
|
||||
],
|
||||
'/adapters/': [
|
||||
{
|
||||
text: 'Adapters Overview',
|
||||
items: [
|
||||
{ text: 'All Adapters', link: '/adapters/' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Browser Adapters',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: 'Twitter / X', link: '/adapters/browser/twitter' },
|
||||
{ text: 'Reddit', link: '/adapters/browser/reddit' },
|
||||
{ text: 'Bilibili', link: '/adapters/browser/bilibili' },
|
||||
{ text: 'Zhihu', link: '/adapters/browser/zhihu' },
|
||||
{ text: 'Xiaohongshu', link: '/adapters/browser/xiaohongshu' },
|
||||
{ text: 'Weibo', link: '/adapters/browser/weibo' },
|
||||
{ text: 'YouTube', link: '/adapters/browser/youtube' },
|
||||
{ text: 'Xueqiu', link: '/adapters/browser/xueqiu' },
|
||||
{ text: 'V2EX', link: '/adapters/browser/v2ex' },
|
||||
{ text: 'LinkedIn', link: '/adapters/browser/linkedin' },
|
||||
{ text: 'Coupang', link: '/adapters/browser/coupang' },
|
||||
{ text: 'BOSS Zhipin', link: '/adapters/browser/boss' },
|
||||
{ text: 'Ctrip', link: '/adapters/browser/ctrip' },
|
||||
{ text: 'Reuters', link: '/adapters/browser/reuters' },
|
||||
{ text: 'SMZDM', link: '/adapters/browser/smzdm' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Public API Adapters',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: 'HackerNews', link: '/adapters/browser/hackernews' },
|
||||
{ text: 'GitHub', link: '/adapters/browser/github' },
|
||||
{ text: 'BBC', link: '/adapters/browser/bbc' },
|
||||
{ text: 'Apple Podcasts', link: '/adapters/browser/apple-podcasts' },
|
||||
{ text: 'Xiaoyuzhou', link: '/adapters/browser/xiaoyuzhou' },
|
||||
{ text: 'Yahoo Finance', link: '/adapters/browser/yahoo-finance' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Desktop Adapters',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: 'Cursor', link: '/adapters/desktop/cursor' },
|
||||
{ text: 'Codex', link: '/adapters/desktop/codex' },
|
||||
{ text: 'Antigravity', link: '/adapters/desktop/antigravity' },
|
||||
{ text: 'ChatGPT', link: '/adapters/desktop/chatgpt' },
|
||||
{ text: 'ChatWise', link: '/adapters/desktop/chatwise' },
|
||||
{ text: 'Notion', link: '/adapters/desktop/notion' },
|
||||
{ text: 'Discord', link: '/adapters/desktop/discord' },
|
||||
{ text: 'Feishu', link: '/adapters/desktop/feishu' },
|
||||
{ text: 'WeChat', link: '/adapters/desktop/wechat' },
|
||||
{ text: 'NeteaseMusic', link: '/adapters/desktop/neteasemusic' },
|
||||
],
|
||||
},
|
||||
],
|
||||
'/developer/': [
|
||||
{
|
||||
text: 'Developer Guide',
|
||||
items: [
|
||||
{ text: 'Contributing', link: '/developer/contributing' },
|
||||
{ text: 'Testing', link: '/developer/testing' },
|
||||
{ text: 'Architecture', link: '/developer/architecture' },
|
||||
{ text: 'YAML Adapter Guide', link: '/developer/yaml-adapter' },
|
||||
{ text: 'TypeScript Adapter Guide', link: '/developer/ts-adapter' },
|
||||
{ text: 'AI Workflow', link: '/developer/ai-workflow' },
|
||||
],
|
||||
},
|
||||
],
|
||||
'/advanced/': [
|
||||
{
|
||||
text: 'Advanced',
|
||||
items: [
|
||||
{ text: 'Chrome DevTools Protocol', link: '/advanced/cdp' },
|
||||
{ text: 'Electron Apps', link: '/advanced/electron' },
|
||||
{ text: 'Remote Chrome', link: '/advanced/remote-chrome' },
|
||||
{ text: 'Download Support', link: '/advanced/download' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
zh: {
|
||||
label: '中文',
|
||||
lang: 'zh-CN',
|
||||
link: '/zh/',
|
||||
themeConfig: {
|
||||
nav: [
|
||||
{ text: '指南', link: '/zh/guide/getting-started' },
|
||||
{ text: '适配器', link: '/zh/adapters/' },
|
||||
{ text: '开发者', link: '/zh/developer/contributing' },
|
||||
{ text: '进阶', link: '/zh/advanced/cdp' },
|
||||
],
|
||||
sidebar: {
|
||||
'/zh/guide/': [
|
||||
{
|
||||
text: '指南',
|
||||
items: [
|
||||
{ text: '快速开始', link: '/zh/guide/getting-started' },
|
||||
{ text: '安装', link: '/zh/guide/installation' },
|
||||
{ text: 'Browser Bridge', link: '/zh/guide/browser-bridge' },
|
||||
{ text: '问题排查', link: '/zh/guide/troubleshooting' },
|
||||
],
|
||||
},
|
||||
],
|
||||
'/zh/adapters/': [
|
||||
{
|
||||
text: '适配器概览',
|
||||
items: [
|
||||
{ text: '所有适配器', link: '/zh/adapters/' },
|
||||
],
|
||||
},
|
||||
],
|
||||
'/zh/developer/': [
|
||||
{
|
||||
text: '开发者指南',
|
||||
items: [
|
||||
{ text: '贡献指南', link: '/zh/developer/contributing' },
|
||||
{ text: '测试', link: '/zh/developer/testing' },
|
||||
],
|
||||
},
|
||||
],
|
||||
'/zh/advanced/': [
|
||||
{
|
||||
text: '进阶',
|
||||
items: [
|
||||
{ text: 'Chrome DevTools Protocol', link: '/zh/advanced/cdp' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
themeConfig: {
|
||||
search: {
|
||||
provider: 'local',
|
||||
},
|
||||
|
||||
socialLinks: [
|
||||
{ icon: 'github', link: 'https://github.com/jackwener/opencli' },
|
||||
{ icon: 'npm', link: 'https://www.npmjs.com/package/@jackwener/opencli' },
|
||||
],
|
||||
|
||||
editLink: {
|
||||
pattern: 'https://github.com/jackwener/opencli/edit/main/docs/:path',
|
||||
text: 'Edit this page on GitHub',
|
||||
},
|
||||
|
||||
footer: {
|
||||
message: 'Released under the Apache-2.0 License.',
|
||||
copyright: 'Copyright © 2024-present jackwener',
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,28 @@
|
||||
# Apple Podcasts
|
||||
|
||||
**Mode**: 🌐 Public · **Domain**: `podcasts.apple.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli apple-podcasts search` | |
|
||||
| `opencli apple-podcasts episodes` | |
|
||||
| `opencli apple-podcasts top` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli apple-podcasts search --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli apple-podcasts search -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli apple-podcasts search -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- No browser required — uses public API
|
||||
@@ -0,0 +1,26 @@
|
||||
# BBC News
|
||||
|
||||
**Mode**: 🌐 Public · **Domain**: `bbc.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli bbc news` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli bbc news --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli bbc news -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli bbc news -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- No browser required — uses public API
|
||||
@@ -0,0 +1,38 @@
|
||||
# Bilibili
|
||||
|
||||
**Mode**: 🔐 Browser · **Domain**: `bilibili.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli bilibili hot` | |
|
||||
| `opencli bilibili search` | |
|
||||
| `opencli bilibili me` | |
|
||||
| `opencli bilibili favorite` | |
|
||||
| `opencli bilibili history` | |
|
||||
| `opencli bilibili feed` | |
|
||||
| `opencli bilibili subtitle` | |
|
||||
| `opencli bilibili dynamic` | |
|
||||
| `opencli bilibili ranking` | |
|
||||
| `opencli bilibili following` | |
|
||||
| `opencli bilibili user-videos` | |
|
||||
| `opencli bilibili download` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli bilibili hot --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli bilibili hot -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli bilibili hot -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Chrome running and **logged into** bilibili.com
|
||||
- [Browser Bridge extension](/guide/browser-bridge) installed
|
||||
@@ -0,0 +1,28 @@
|
||||
# BOSS Zhipin
|
||||
|
||||
**Mode**: 🔐 Browser · **Domain**: `zhipin.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli boss search` | |
|
||||
| `opencli boss detail` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli boss search --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli boss search -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli boss search -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Chrome running and **logged into** zhipin.com
|
||||
- [Browser Bridge extension](/guide/browser-bridge) installed
|
||||
@@ -0,0 +1,28 @@
|
||||
# Coupang
|
||||
|
||||
**Mode**: 🔐 Browser · **Domain**: `coupang.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli coupang search` | |
|
||||
| `opencli coupang add-to-cart` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli coupang search --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli coupang search -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli coupang search -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Chrome running and **logged into** coupang.com
|
||||
- [Browser Bridge extension](/guide/browser-bridge) installed
|
||||
@@ -0,0 +1,27 @@
|
||||
# Ctrip (携程)
|
||||
|
||||
**Mode**: 🔐 Browser · **Domain**: `ctrip.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli ctrip search` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli ctrip search --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli ctrip search -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli ctrip search -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Chrome running and **logged into** ctrip.com
|
||||
- [Browser Bridge extension](/guide/browser-bridge) installed
|
||||
@@ -0,0 +1,26 @@
|
||||
# GitHub
|
||||
|
||||
**Mode**: 🌐 Public · **Domain**: `github.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli github search` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli github search --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli github search -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli github search -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- No browser required — uses public API
|
||||
@@ -0,0 +1,26 @@
|
||||
# HackerNews
|
||||
|
||||
**Mode**: 🌐 Public · **Domain**: `news.ycombinator.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli hackernews top` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli hackernews top --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli hackernews top -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli hackernews top -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- No browser required — uses public API
|
||||
@@ -0,0 +1,27 @@
|
||||
# LinkedIn
|
||||
|
||||
**Mode**: 🔐 Browser · **Domain**: `linkedin.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli linkedin search` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli linkedin search --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli linkedin search -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli linkedin search -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Chrome running and **logged into** linkedin.com
|
||||
- [Browser Bridge extension](/guide/browser-bridge) installed
|
||||
@@ -0,0 +1,41 @@
|
||||
# Reddit
|
||||
|
||||
**Mode**: 🔐 Browser · **Domain**: `reddit.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli reddit hot` | |
|
||||
| `opencli reddit frontpage` | |
|
||||
| `opencli reddit popular` | |
|
||||
| `opencli reddit search` | |
|
||||
| `opencli reddit subreddit` | |
|
||||
| `opencli reddit read` | |
|
||||
| `opencli reddit user` | |
|
||||
| `opencli reddit user-posts` | |
|
||||
| `opencli reddit user-comments` | |
|
||||
| `opencli reddit upvote` | |
|
||||
| `opencli reddit save` | |
|
||||
| `opencli reddit comment` | |
|
||||
| `opencli reddit subscribe` | |
|
||||
| `opencli reddit saved` | |
|
||||
| `opencli reddit upvoted` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli reddit hot --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli reddit hot -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli reddit hot -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Chrome running and **logged into** reddit.com
|
||||
- [Browser Bridge extension](/guide/browser-bridge) installed
|
||||
@@ -0,0 +1,27 @@
|
||||
# Reuters
|
||||
|
||||
**Mode**: 🔐 Browser · **Domain**: `reuters.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli reuters search` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli reuters search --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli reuters search -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli reuters search -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Chrome running and **logged into** reuters.com
|
||||
- [Browser Bridge extension](/guide/browser-bridge) installed
|
||||
@@ -0,0 +1,27 @@
|
||||
# SMZDM (什么值得买)
|
||||
|
||||
**Mode**: 🔐 Browser · **Domain**: `smzdm.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli smzdm search` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli smzdm search --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli smzdm search -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli smzdm search -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Chrome running and **logged into** smzdm.com
|
||||
- [Browser Bridge extension](/guide/browser-bridge) installed
|
||||
@@ -0,0 +1,47 @@
|
||||
# Twitter / X
|
||||
|
||||
**Mode**: 🔐 Browser · **Domain**: `twitter.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli twitter trending` | |
|
||||
| `opencli twitter bookmarks` | |
|
||||
| `opencli twitter profile` | |
|
||||
| `opencli twitter search` | |
|
||||
| `opencli twitter timeline` | |
|
||||
| `opencli twitter thread` | |
|
||||
| `opencli twitter following` | |
|
||||
| `opencli twitter followers` | |
|
||||
| `opencli twitter notifications` | |
|
||||
| `opencli twitter post` | |
|
||||
| `opencli twitter reply` | |
|
||||
| `opencli twitter delete` | |
|
||||
| `opencli twitter like` | |
|
||||
| `opencli twitter article` | |
|
||||
| `opencli twitter follow` | |
|
||||
| `opencli twitter unfollow` | |
|
||||
| `opencli twitter bookmark` | |
|
||||
| `opencli twitter unbookmark` | |
|
||||
| `opencli twitter download` | |
|
||||
| `opencli twitter accept` | |
|
||||
| `opencli twitter reply-dm` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli twitter trending --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli twitter trending -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli twitter trending -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Chrome running and **logged into** twitter.com
|
||||
- [Browser Bridge extension](/guide/browser-bridge) installed
|
||||
@@ -0,0 +1,32 @@
|
||||
# V2EX
|
||||
|
||||
**Mode**: 🌐 / 🔐 · **Domain**: `v2ex.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli v2ex hot` | |
|
||||
| `opencli v2ex latest` | |
|
||||
| `opencli v2ex topic` | |
|
||||
| `opencli v2ex daily` | |
|
||||
| `opencli v2ex me` | |
|
||||
| `opencli v2ex notifications` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli v2ex hot --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli v2ex hot -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli v2ex hot -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Chrome running and **logged into** v2ex.com
|
||||
- [Browser Bridge extension](/guide/browser-bridge) installed
|
||||
@@ -0,0 +1,27 @@
|
||||
# Weibo (微博)
|
||||
|
||||
**Mode**: 🔐 Browser · **Domain**: `weibo.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli weibo hot` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli weibo hot --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli weibo hot -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli weibo hot -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Chrome running and **logged into** weibo.com
|
||||
- [Browser Bridge extension](/guide/browser-bridge) installed
|
||||
@@ -0,0 +1,32 @@
|
||||
# Xiaohongshu (小红书)
|
||||
|
||||
**Mode**: 🔐 Browser · **Domain**: `xiaohongshu.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli xiaohongshu search` | |
|
||||
| `opencli xiaohongshu notifications` | |
|
||||
| `opencli xiaohongshu feed` | |
|
||||
| `opencli xiaohongshu me` | |
|
||||
| `opencli xiaohongshu user` | |
|
||||
| `opencli xiaohongshu download` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli xiaohongshu search --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli xiaohongshu search -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli xiaohongshu search -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Chrome running and **logged into** xiaohongshu.com
|
||||
- [Browser Bridge extension](/guide/browser-bridge) installed
|
||||
@@ -0,0 +1,28 @@
|
||||
# Xiaoyuzhou (小宇宙)
|
||||
|
||||
**Mode**: 🌐 Public · **Domain**: `xiaoyuzhou.fm`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli xiaoyuzhou podcast` | |
|
||||
| `opencli xiaoyuzhou podcast-episodes` | |
|
||||
| `opencli xiaoyuzhou episode` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli xiaoyuzhou podcast --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli xiaoyuzhou podcast -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli xiaoyuzhou podcast -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- No browser required — uses public API
|
||||
@@ -0,0 +1,32 @@
|
||||
# Xueqiu (雪球)
|
||||
|
||||
**Mode**: 🔐 Browser · **Domain**: `xueqiu.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli xueqiu feed` | |
|
||||
| `opencli xueqiu hot-stock` | |
|
||||
| `opencli xueqiu hot` | |
|
||||
| `opencli xueqiu search` | |
|
||||
| `opencli xueqiu stock` | |
|
||||
| `opencli xueqiu watchlist` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli xueqiu feed --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli xueqiu feed -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli xueqiu feed -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Chrome running and **logged into** xueqiu.com
|
||||
- [Browser Bridge extension](/guide/browser-bridge) installed
|
||||
@@ -0,0 +1,26 @@
|
||||
# Yahoo Finance
|
||||
|
||||
**Mode**: 🌐 Public · **Domain**: `finance.yahoo.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli yahoo-finance quote` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli yahoo-finance quote --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli yahoo-finance quote -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli yahoo-finance quote -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- No browser required — uses public API
|
||||
@@ -0,0 +1,29 @@
|
||||
# YouTube
|
||||
|
||||
**Mode**: 🔐 Browser · **Domain**: `youtube.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli youtube search` | |
|
||||
| `opencli youtube video` | |
|
||||
| `opencli youtube transcript` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli youtube search --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli youtube search -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli youtube search -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Chrome running and **logged into** youtube.com
|
||||
- [Browser Bridge extension](/guide/browser-bridge) installed
|
||||
@@ -0,0 +1,30 @@
|
||||
# Zhihu
|
||||
|
||||
**Mode**: 🔐 Browser · **Domain**: `zhihu.com`
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli zhihu hot` | |
|
||||
| `opencli zhihu search` | |
|
||||
| `opencli zhihu question` | |
|
||||
| `opencli zhihu download` | |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Quick start
|
||||
opencli zhihu hot --limit 5
|
||||
|
||||
# JSON output
|
||||
opencli zhihu hot -f json
|
||||
|
||||
# Verbose mode
|
||||
opencli zhihu hot -v
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Chrome running and **logged into** zhihu.com
|
||||
- [Browser Bridge extension](/guide/browser-bridge) installed
|
||||
@@ -0,0 +1,46 @@
|
||||
# Antigravity
|
||||
|
||||
🔥 **CLI All Electron Apps! The Most Powerful Update Has Arrived!** 🔥
|
||||
|
||||
Turn your local Antigravity desktop application into a programmable AI node via Chrome DevTools Protocol (CDP). This allows you to compose complex LLM workflows entirely through the terminal by manipulating the actual UI natively, bypassing any API restrictions.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Start the Antigravity desktop app with the Chrome DevTools `remote-debugging-port` flag:
|
||||
|
||||
```bash
|
||||
# Start Antigravity in the background
|
||||
/Applications/Antigravity.app/Contents/MacOS/Electron \
|
||||
--remote-debugging-port=9224
|
||||
```
|
||||
|
||||
> Depending on your installation, the executable might be named differently, e.g., `Antigravity` instead of `Electron`.
|
||||
|
||||
Then set the target port:
|
||||
|
||||
```bash
|
||||
export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9224"
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
### `opencli antigravity status`
|
||||
Check the Chromium CDP connection. Returns the current window title and active internal URL.
|
||||
|
||||
### `opencli antigravity send <message>`
|
||||
Send a text prompt to the AI. Automatically locates the Lexical editor input box, types the prompt securely, and hits Enter.
|
||||
|
||||
### `opencli antigravity read`
|
||||
Scrape the entire current conversation history block as pure text.
|
||||
|
||||
### `opencli antigravity new`
|
||||
Click the "New Conversation" button to instantly clear the UI state and start fresh.
|
||||
|
||||
### `opencli antigravity extract-code`
|
||||
Extract any multi-line code blocks from the current conversation view. Ideal for automated script extraction (e.g. `opencli antigravity extract-code > script.sh`).
|
||||
|
||||
### `opencli antigravity model <name>`
|
||||
Quickly target and switch the active LLM engine. Example: `opencli antigravity model claude` or `opencli antigravity model gemini`.
|
||||
|
||||
### `opencli antigravity watch`
|
||||
A long-running, streaming process that continuously polls the Antigravity UI for chat updates and outputs them in real-time to standard output.
|
||||
@@ -0,0 +1,43 @@
|
||||
# ChatGPT
|
||||
|
||||
Control the **ChatGPT macOS Desktop App** directly from the terminal. OpenCLI supports two automation approaches for ChatGPT.
|
||||
|
||||
## Approach 1: AppleScript (Default, No Setup)
|
||||
|
||||
The current built-in commands use native AppleScript automation — no extra launch flags needed.
|
||||
|
||||
### Prerequisites
|
||||
1. Install the official [ChatGPT Desktop App](https://openai.com/chatgpt/mac/) from OpenAI.
|
||||
2. Grant **Accessibility permissions** to your terminal app in **System Settings → Privacy & Security → Accessibility**.
|
||||
|
||||
### Commands
|
||||
- `opencli chatgpt status`: Check if the ChatGPT app is currently running.
|
||||
- `opencli chatgpt new`: Activate ChatGPT and press `Cmd+N` to start a new conversation.
|
||||
- `opencli chatgpt send "message"`: Copy your message to clipboard, activate ChatGPT, paste, and submit.
|
||||
- `opencli chatgpt read`: Copy the last AI response via `Cmd+Shift+C` and return it as text.
|
||||
|
||||
## Approach 2: CDP (Advanced, Electron Debug Mode)
|
||||
|
||||
ChatGPT Desktop is also an Electron app and can be launched with a remote debugging port:
|
||||
|
||||
```bash
|
||||
/Applications/ChatGPT.app/Contents/MacOS/ChatGPT \
|
||||
--remote-debugging-port=9224
|
||||
```
|
||||
|
||||
```bash
|
||||
export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9224"
|
||||
```
|
||||
|
||||
> The CDP approach enables future advanced commands like DOM inspection, model switching, and code extraction.
|
||||
|
||||
## How It Works
|
||||
|
||||
- **AppleScript mode**: Uses `osascript` and `pbcopy`/`pbpaste` for clipboard-based text transfer.
|
||||
- **CDP mode**: Connects via Chrome DevTools Protocol to the Electron renderer process.
|
||||
|
||||
## Limitations
|
||||
|
||||
- macOS only (AppleScript dependency)
|
||||
- AppleScript mode requires Accessibility permissions
|
||||
- `read` command copies the last response — earlier messages need manual scroll
|
||||
@@ -0,0 +1,38 @@
|
||||
# ChatWise
|
||||
|
||||
Control the **ChatWise Desktop App** from the terminal via Chrome DevTools Protocol (CDP). ChatWise is an Electron-based multi-LLM client supporting GPT-4, Claude, Gemini, and more.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Install [ChatWise](https://chatwise.app/).
|
||||
2. Launch with remote debugging port:
|
||||
```bash
|
||||
/Applications/ChatWise.app/Contents/MacOS/ChatWise \
|
||||
--remote-debugging-port=9228
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9228"
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
### Diagnostics
|
||||
- `opencli chatwise status`: Check CDP connection status.
|
||||
- `opencli chatwise screenshot`: Export DOM + accessibility snapshot.
|
||||
|
||||
### Chat
|
||||
- `opencli chatwise new`: Start a new conversation (`Cmd+N`).
|
||||
- `opencli chatwise send "message"`: Send a message to the active chat.
|
||||
- `opencli chatwise read`: Read the current conversation.
|
||||
- `opencli chatwise ask "prompt"`: Send + wait for response + return it (one-shot).
|
||||
|
||||
### AI Features
|
||||
- `opencli chatwise model`: Get the current AI model.
|
||||
- `opencli chatwise model gpt-4`: Switch to a different model.
|
||||
|
||||
### Organization
|
||||
- `opencli chatwise history`: List conversations from the sidebar.
|
||||
- `opencli chatwise export`: Export conversation as Markdown.
|
||||
@@ -0,0 +1,32 @@
|
||||
# Codex
|
||||
|
||||
Control the **OpenAI Codex Desktop App** headless or headfully via Chrome DevTools Protocol (CDP). Because Codex is built on Electron, OpenCLI can directly drive its internal UI, automate slash commands, and manipulate its AI agent threads.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. You must have the official OpenAI Codex app installed.
|
||||
2. Launch it via the terminal and expose the remote debugging port:
|
||||
```bash
|
||||
# macOS
|
||||
/Applications/Codex.app/Contents/MacOS/Codex --remote-debugging-port=9222
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
export OPENCLI_CODEX_CDP_ENDPOINT="http://127.0.0.1:9222"
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
### Diagnostics
|
||||
- `opencli codex status`: Checks connection and reads the current active window URL/title.
|
||||
- `opencli codex dump`: Dumps the full UI DOM and Accessibility tree into `/tmp`.
|
||||
|
||||
### Agent Manipulation
|
||||
- `opencli codex new`: Simulates `Cmd+N` to start a completely fresh and isolated Git Worktree thread context.
|
||||
- `opencli codex send "message"`: Robustly finds the active Thread Composer and injects your text.
|
||||
- *Pro-tip*: You can trigger internal shortcuts, e.g., `opencli codex send "/review"`.
|
||||
- `opencli codex read`: Extracts the entire current thread history and AI reasoning logs.
|
||||
- `opencli codex extract-diff`: Automatically scrapes any visual Patch chunks and Code Diffs.
|
||||
- `opencli codex model`: Get the currently active AI model.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Cursor
|
||||
|
||||
Control the **Cursor IDE** from the terminal via Chrome DevTools Protocol (CDP). Since Cursor is built on Electron (VS Code fork), OpenCLI can drive its internal UI, automate Composer interactions, and manipulate chat sessions.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Install [Cursor](https://cursor.sh/).
|
||||
2. Launch it with the remote debugging port:
|
||||
```bash
|
||||
/Applications/Cursor.app/Contents/MacOS/Cursor --remote-debugging-port=9226
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9226"
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
### Diagnostics
|
||||
- `opencli cursor status`: Check CDP connection status.
|
||||
- `opencli cursor dump`: Dump the full DOM and Accessibility snapshot to `/tmp/cursor-dom.html` and `/tmp/cursor-snapshot.json`.
|
||||
|
||||
### Chat Manipulation
|
||||
- `opencli cursor new`: Press `Cmd+N` to start a new file/tab.
|
||||
- `opencli cursor send "message"`: Inject text into the active Composer/Chat input and submit.
|
||||
- `opencli cursor read`: Extract the full conversation history from the active chat panel.
|
||||
|
||||
### AI Features
|
||||
- `opencli cursor composer "prompt"`: Open the Composer panel (`Cmd+I`) and send a prompt for inline AI editing.
|
||||
- `opencli cursor model`: Get the currently active AI model (e.g., `claude-4.5-sonnet`).
|
||||
- `opencli cursor extract-code`: Extract all code blocks from the current conversation.
|
||||
@@ -0,0 +1,28 @@
|
||||
# Discord
|
||||
|
||||
Control the **Discord Desktop App** from the terminal via Chrome DevTools Protocol (CDP).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Launch with remote debugging port:
|
||||
```bash
|
||||
/Applications/Discord.app/Contents/MacOS/Discord --remote-debugging-port=9232
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9232"
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli discord status` | Check CDP connection |
|
||||
| `opencli discord send "message"` | Send a message in the active channel |
|
||||
| `opencli discord read` | Read recent messages |
|
||||
| `opencli discord channels` | List channels in the current server |
|
||||
| `opencli discord servers` | List all joined servers |
|
||||
| `opencli discord search "query"` | Search messages (Cmd+F) |
|
||||
| `opencli discord members` | List online members |
|
||||
@@ -0,0 +1,20 @@
|
||||
# Feishu (飞书/Lark)
|
||||
|
||||
Control **Feishu/Lark Desktop** from the terminal via AppleScript.
|
||||
|
||||
> **Note:** Feishu uses a custom `Lark Framework` (Chromium-based but NOT Electron). CDP is not available, so this adapter uses AppleScript + clipboard.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Feishu/Lark must be running and logged in
|
||||
2. Terminal must have **Accessibility permission**
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli feishu status` | Check if Feishu/Lark is running |
|
||||
| `opencli feishu send "msg"` | Send message in active chat (paste + Enter) |
|
||||
| `opencli feishu read` | Read current chat (Cmd+A → Cmd+C) |
|
||||
| `opencli feishu search "query"` | Global search (Cmd+K) |
|
||||
| `opencli feishu new` | New message/document (Cmd+N) |
|
||||
@@ -0,0 +1,31 @@
|
||||
# NeteaseMusic (网易云音乐)
|
||||
|
||||
Control **NeteaseMusic** (网易云音乐) from the terminal via Chrome DevTools Protocol (CDP). The app uses Chromium Embedded Framework (CEF).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Launch with remote debugging port:
|
||||
```bash
|
||||
/Applications/NeteaseMusic.app/Contents/MacOS/NeteaseMusic --remote-debugging-port=9234
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9234"
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli neteasemusic status` | Check CDP connection |
|
||||
| `opencli neteasemusic playing` | Current song info (title, artist, album) |
|
||||
| `opencli neteasemusic play` | Play / Pause toggle |
|
||||
| `opencli neteasemusic next` | Skip to next song |
|
||||
| `opencli neteasemusic prev` | Go to previous song |
|
||||
| `opencli neteasemusic search "query"` | Search songs, artists |
|
||||
| `opencli neteasemusic playlist` | Show current playback queue |
|
||||
| `opencli neteasemusic like` | Like / unlike current song |
|
||||
| `opencli neteasemusic lyrics` | Get lyrics of current song |
|
||||
| `opencli neteasemusic volume [0-100]` | Get or set volume |
|
||||
@@ -0,0 +1,29 @@
|
||||
# Notion
|
||||
|
||||
Control the **Notion Desktop App** from the terminal via Chrome DevTools Protocol (CDP).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Launch with remote debugging port:
|
||||
```bash
|
||||
/Applications/Notion.app/Contents/MacOS/Notion --remote-debugging-port=9230
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9230"
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli notion status` | Check CDP connection |
|
||||
| `opencli notion search "query"` | Quick Find search (Cmd+P) |
|
||||
| `opencli notion read` | Read the current page content |
|
||||
| `opencli notion new "title"` | Create a new page (Cmd+N) |
|
||||
| `opencli notion write "text"` | Append text to the current page |
|
||||
| `opencli notion sidebar` | List pages from the sidebar |
|
||||
| `opencli notion favorites` | List pages from the Favorites section |
|
||||
| `opencli notion export` | Export page as Markdown |
|
||||
@@ -0,0 +1,28 @@
|
||||
# WeChat (微信)
|
||||
|
||||
Control **WeChat Mac Desktop** from the terminal via AppleScript + Accessibility API.
|
||||
|
||||
> **Note:** WeChat is a native macOS app (not Electron), so CDP is not available. This adapter uses AppleScript keyboard simulation and clipboard operations.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. WeChat must be running and logged in
|
||||
2. Terminal must have **Accessibility permission** (System Settings → Privacy & Security → Accessibility)
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `opencli wechat status` | Check if WeChat is running |
|
||||
| `opencli wechat send "msg"` | Send message in the active chat (clipboard paste + Enter) |
|
||||
| `opencli wechat read` | Read current chat content (Cmd+A → Cmd+C) |
|
||||
| `opencli wechat search "keyword"` | Open search and type a query (Cmd+F) |
|
||||
| `opencli wechat chats` | Switch to Chats tab (Cmd+1) |
|
||||
| `opencli wechat contacts` | Switch to Contacts tab (Cmd+2) |
|
||||
|
||||
## Limitations
|
||||
|
||||
- **No CDP support** — WeChat is native Cocoa, not Electron
|
||||
- `send` requires the correct conversation to be already open
|
||||
- `read` captures whatever is visible via select-all + copy
|
||||
- `search` types the query but cannot programmatically click results
|
||||
@@ -0,0 +1,49 @@
|
||||
# All Adapters
|
||||
|
||||
Run `opencli list` for the live registry.
|
||||
|
||||
## Browser Adapters
|
||||
|
||||
| Site | Commands | Mode |
|
||||
|------|----------|------|
|
||||
| **[twitter](/adapters/browser/twitter)** | `trending` `bookmarks` `profile` `search` `timeline` `thread` `following` `followers` `notifications` `post` `reply` `delete` `like` `article` `follow` `unfollow` `bookmark` `unbookmark` `download` `accept` `reply-dm` | 🔐 Browser |
|
||||
| **[reddit](/adapters/browser/reddit)** | `hot` `frontpage` `popular` `search` `subreddit` `read` `user` `user-posts` `user-comments` `upvote` `save` `comment` `subscribe` `saved` `upvoted` | 🔐 Browser |
|
||||
| **[bilibili](/adapters/browser/bilibili)** | `hot` `search` `me` `favorite` `history` `feed` `subtitle` `dynamic` `ranking` `following` `user-videos` `download` | 🔐 Browser |
|
||||
| **[zhihu](/adapters/browser/zhihu)** | `hot` `search` `question` `download` | 🔐 Browser |
|
||||
| **[xiaohongshu](/adapters/browser/xiaohongshu)** | `search` `notifications` `feed` `me` `user` `download` | 🔐 Browser |
|
||||
| **[xueqiu](/adapters/browser/xueqiu)** | `feed` `hot-stock` `hot` `search` `stock` `watchlist` | 🔐 Browser |
|
||||
| **[youtube](/adapters/browser/youtube)** | `search` `video` `transcript` | 🔐 Browser |
|
||||
| **[v2ex](/adapters/browser/v2ex)** | `hot` `latest` `topic` `daily` `me` `notifications` | 🌐 / 🔐 |
|
||||
| **[weibo](/adapters/browser/weibo)** | `hot` | 🔐 Browser |
|
||||
| **[linkedin](/adapters/browser/linkedin)** | `search` | 🔐 Browser |
|
||||
| **[coupang](/adapters/browser/coupang)** | `search` `add-to-cart` | 🔐 Browser |
|
||||
| **[boss](/adapters/browser/boss)** | `search` `detail` | 🔐 Browser |
|
||||
| **[ctrip](/adapters/browser/ctrip)** | `search` | 🔐 Browser |
|
||||
| **[reuters](/adapters/browser/reuters)** | `search` | 🔐 Browser |
|
||||
| **[smzdm](/adapters/browser/smzdm)** | `search` | 🔐 Browser |
|
||||
|
||||
## Public API Adapters
|
||||
|
||||
| Site | Commands | Mode |
|
||||
|------|----------|------|
|
||||
| **[hackernews](/adapters/browser/hackernews)** | `top` | 🌐 Public |
|
||||
| **[github](/adapters/browser/github)** | `search` | 🌐 Public |
|
||||
| **[bbc](/adapters/browser/bbc)** | `news` | 🌐 Public |
|
||||
| **[apple-podcasts](/adapters/browser/apple-podcasts)** | `search` `episodes` `top` | 🌐 Public |
|
||||
| **[xiaoyuzhou](/adapters/browser/xiaoyuzhou)** | `podcast` `podcast-episodes` `episode` | 🌐 Public |
|
||||
| **[yahoo-finance](/adapters/browser/yahoo-finance)** | `quote` | 🌐 Public |
|
||||
|
||||
## Desktop Adapters
|
||||
|
||||
| App | Description | Commands |
|
||||
|-----|-------------|----------|
|
||||
| **[Cursor](/adapters/desktop/cursor)** | Control Cursor IDE | `status` `send` `read` `new` `dump` `composer` `model` `extract-code` `ask` `screenshot` `history` `export` |
|
||||
| **[Codex](/adapters/desktop/codex)** | Drive OpenAI Codex CLI agent | `status` `send` `read` `new` `extract-diff` `model` `ask` `screenshot` `history` `export` |
|
||||
| **[Antigravity](/adapters/desktop/antigravity)** | Control Antigravity Ultra | `status` `send` `read` `new` `dump` `extract-code` `model` `watch` |
|
||||
| **[ChatGPT](/adapters/desktop/chatgpt)** | Automate ChatGPT macOS app | `status` `new` `send` `read` `ask` |
|
||||
| **[ChatWise](/adapters/desktop/chatwise)** | Multi-LLM client | `status` `new` `send` `read` `ask` `model` `history` `export` `screenshot` |
|
||||
| **[Notion](/adapters/desktop/notion)** | Search, read, write pages | `status` `search` `read` `new` `write` `sidebar` `favorites` `export` |
|
||||
| **[Discord](/adapters/desktop/discord)** | Desktop messages & channels | `status` `send` `read` `channels` `servers` `search` `members` |
|
||||
| **[Feishu](/adapters/desktop/feishu)** | 飞书/Lark via AppleScript | `status` `send` `read` `search` `new` |
|
||||
| **[WeChat](/adapters/desktop/wechat)** | 微信 via AppleScript | `status` `send` `read` `search` `chats` `contacts` |
|
||||
| **[NeteaseMusic](/adapters/desktop/neteasemusic)** | 网易云音乐 via CDP | `status` `playing` `play` `next` `prev` `search` `playlist` `like` `lyrics` `volume` |
|
||||
@@ -0,0 +1,103 @@
|
||||
# Connecting OpenCLI via CDP (Remote/Headless Servers)
|
||||
|
||||
If you cannot use the opencli Browser Bridge extension (e.g., in a remote headless server environment without a UI), OpenCLI provides an alternative: connecting directly to Chrome via **CDP (Chrome DevTools Protocol)**.
|
||||
|
||||
Because CDP binds to `localhost` by default for security reasons, accessing it from a remote server requires an additional networking tunnel.
|
||||
|
||||
This guide is broken down into three phases:
|
||||
1. **Preparation**: Start Chrome with CDP enabled locally.
|
||||
2. **Network Tunnels**: Expose that CDP port to your remote server using either **SSH Tunnels** or **Reverse Proxies**.
|
||||
3. **Execution**: Run OpenCLI on your server.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Preparation (Local Machine)
|
||||
|
||||
First, you need to start a Chrome browser on your local machine with remote debugging enabled.
|
||||
|
||||
**macOS:**
|
||||
```bash
|
||||
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
|
||||
--remote-debugging-port=9222 \
|
||||
--user-data-dir="$HOME/chrome-debug-profile" \
|
||||
--remote-allow-origins="*"
|
||||
```
|
||||
|
||||
**Linux:**
|
||||
```bash
|
||||
google-chrome \
|
||||
--remote-debugging-port=9222 \
|
||||
--user-data-dir="$HOME/chrome-debug-profile" \
|
||||
--remote-allow-origins="*"
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```cmd
|
||||
"C:\Program Files\Google\Chrome\Application\chrome.exe" ^
|
||||
--remote-debugging-port=9222 ^
|
||||
--user-data-dir="%USERPROFILE%\chrome-debug-profile" ^
|
||||
--remote-allow-origins="*"
|
||||
```
|
||||
|
||||
> **Note**: The `--remote-allow-origins="*"` flag is often required for modern Chrome versions to accept cross-origin CDP WebSocket connections (e.g. from reverse proxies like ngrok).
|
||||
|
||||
Once this browser instance opens, **log into the target websites you want to use** (e.g., bilibili.com, zhihu.com) so that the session contains the correct cookies.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Remote Access Methods
|
||||
|
||||
Once CDP is running locally on port `9222`, you must securely expose this port to your remote server. Choose one of the two methods below depending on your network conditions.
|
||||
|
||||
### Method A: SSH Tunnel (Recommended)
|
||||
|
||||
If your local machine has SSH access to the remote server, this is the most secure and straightforward method.
|
||||
|
||||
Run this command on your **Local Machine** to forward the remote server's port `9222` back to your local port `9222`:
|
||||
|
||||
```bash
|
||||
ssh -R 9222:localhost:9222 your-server-user@your-server-ip
|
||||
```
|
||||
|
||||
Leave this SSH session running in the background.
|
||||
|
||||
### Method B: Reverse Proxy (ngrok / frp / socat)
|
||||
|
||||
If you cannot establish a direct SSH connection (e.g., due to NAT or firewalls), you can use an intranet penetration tool like `ngrok`.
|
||||
|
||||
Run this command on your **Local Machine** to expose your local port `9222` to the public internet securely via ngrok:
|
||||
|
||||
```bash
|
||||
ngrok http 9222
|
||||
```
|
||||
|
||||
This will print a forwarding URL, such as `https://abcdef.ngrok.app`. **Copy this URL**.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Execution (Remote Server)
|
||||
|
||||
Now switch to your **Remote Server** where OpenCLI is installed.
|
||||
|
||||
Depending on the network tunnel method you chose in Phase 2, set the `OPENCLI_CDP_ENDPOINT` environment variable and run your commands.
|
||||
|
||||
### If you used Method A (SSH Tunnel):
|
||||
|
||||
```bash
|
||||
export OPENCLI_CDP_ENDPOINT="http://localhost:9222"
|
||||
opencli doctor # Verify connection
|
||||
opencli bilibili hot --limit 5 # Test a command
|
||||
```
|
||||
|
||||
### If you used Method B (Reverse Proxy like ngrok):
|
||||
|
||||
```bash
|
||||
# Use the URL you copied from ngrok earlier
|
||||
export OPENCLI_CDP_ENDPOINT="https://abcdef.ngrok.app"
|
||||
opencli doctor # Verify connection
|
||||
opencli bilibili hot --limit 5 # Test a command
|
||||
```
|
||||
|
||||
> *Tip: If you provide a standard HTTP/HTTPS CDP endpoint, OpenCLI requests the `/json` target list and picks the most likely inspectable app/page target automatically. If multiple app targets exist, you can further narrow selection with `OPENCLI_CDP_TARGET` (for example `antigravity` or `codex`).*
|
||||
|
||||
If you plan to use this setup frequently, you can persist the environment variable by adding the `export` line to your `~/.bashrc` or `~/.zshrc` on the server.
|
||||
@@ -0,0 +1,63 @@
|
||||
# Download Support
|
||||
|
||||
OpenCLI supports downloading images, videos, and articles from supported platforms.
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
| Platform | Content Types | Notes |
|
||||
|----------|---------------|-------|
|
||||
| **xiaohongshu** | Images, Videos | Downloads all media from a note |
|
||||
| **bilibili** | Videos | Requires `yt-dlp` installed |
|
||||
| **twitter** | Images, Videos | Downloads from user media tab or single tweet |
|
||||
| **zhihu** | Articles (Markdown) | Exports articles with optional image download |
|
||||
|
||||
## Prerequisites
|
||||
|
||||
For video downloads from streaming platforms, install `yt-dlp`:
|
||||
|
||||
```bash
|
||||
# Install yt-dlp
|
||||
pip install yt-dlp
|
||||
# or
|
||||
brew install yt-dlp
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Download images/videos from Xiaohongshu note
|
||||
opencli xiaohongshu download --note_id abc123 --output ./xhs
|
||||
|
||||
# Download Bilibili video (requires yt-dlp)
|
||||
opencli bilibili download --bvid BV1xxx --output ./bilibili
|
||||
opencli bilibili download --bvid BV1xxx --quality 1080p
|
||||
|
||||
# Download Twitter media from user
|
||||
opencli twitter download --username elonmusk --limit 20 --output ./twitter
|
||||
|
||||
# Download single tweet media
|
||||
opencli twitter download --tweet-url "https://x.com/user/status/123" --output ./twitter
|
||||
|
||||
# Export Zhihu article to Markdown
|
||||
opencli zhihu download --url "https://zhuanlan.zhihu.com/p/xxx" --output ./zhihu
|
||||
|
||||
# Export with local images
|
||||
opencli zhihu download --url "https://zhuanlan.zhihu.com/p/xxx" --download-images
|
||||
```
|
||||
|
||||
## Pipeline Step (YAML Adapters)
|
||||
|
||||
The `download` step can be used in YAML pipelines:
|
||||
|
||||
::: v-pre
|
||||
```yaml
|
||||
pipeline:
|
||||
- fetch: https://api.example.com/media
|
||||
- download:
|
||||
url: ${{ item.imageUrl }}
|
||||
dir: ./downloads
|
||||
filename: ${{ item.title | sanitize }}.jpg
|
||||
concurrency: 5
|
||||
skip_existing: true
|
||||
```
|
||||
:::
|
||||
@@ -0,0 +1,125 @@
|
||||
---
|
||||
description: How to CLI-ify and automate any Electron Desktop Application via CDP
|
||||
---
|
||||
|
||||
# CLI-ifying Electron Applications (Skill Guide)
|
||||
|
||||
Based on the successful automation of **Cursor**, **Codex**, **Antigravity**, **ChatWise**, **Notion**, and **Discord** desktop apps, this guide serves as the standard operating procedure (SOP) for adapting ANY Electron-based application into an OpenCLI adapter.
|
||||
|
||||
## Core Concept
|
||||
|
||||
Electron apps are essentially local Chromium browser instances. By exposing a debugging port (CDP — Chrome DevTools Protocol) at launch time, we can use the Browser Bridge to pierce through the UI layer, accessing and controlling all underlying state including React/Vue components and Shadow DOM.
|
||||
|
||||
> **Note:** Not all desktop apps are Electron. WeChat (native Cocoa) and Feishu/Lark (custom Lark Framework) embed Chromium but do NOT expose CDP. For those apps, use the AppleScript + clipboard approach instead (see [Non-Electron Pattern](#non-electron-pattern-applescript)).
|
||||
|
||||
### Launching the Target App
|
||||
```bash
|
||||
/Applications/AppName.app/Contents/MacOS/AppName --remote-debugging-port=9222
|
||||
```
|
||||
|
||||
### Verifying Electron
|
||||
```bash
|
||||
# Check for Electron Framework in the app bundle
|
||||
ls /Applications/AppName.app/Contents/Frameworks/Electron\ Framework.framework
|
||||
# If this directory exists → Electron → CDP works
|
||||
# If not → check for libEGL.dylib (embedded Chromium/CEF, CDP may not work)
|
||||
```
|
||||
|
||||
## The 5-Command Pattern (CDP / Electron)
|
||||
|
||||
Every new Electron adapter should implement these 5 commands in `src/clis/<app_name>/`:
|
||||
|
||||
### 1. `status.ts` — Connection Test
|
||||
```typescript
|
||||
export const statusCommand = cli({
|
||||
site: 'myapp',
|
||||
name: 'status',
|
||||
domain: 'localhost',
|
||||
strategy: Strategy.UI,
|
||||
browser: true, // Requires CDP connection
|
||||
args: [],
|
||||
columns: ['Status', 'Url', 'Title'],
|
||||
func: async (page: IPage) => {
|
||||
const url = await page.evaluate('window.location.href');
|
||||
const title = await page.evaluate('document.title');
|
||||
return [{ Status: 'Connected', Url: url, Title: title }];
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### 2. `dump.ts` — Reverse Engineering Core
|
||||
Modern app DOMs are huge and obfuscated. **Never guess selectors.** Dump first, then extract precise class names with AI or `grep`:
|
||||
```typescript
|
||||
const dom = await page.evaluate('document.body.innerHTML');
|
||||
fs.writeFileSync('/tmp/app-dom.html', dom);
|
||||
const snap = await page.snapshot({ interactive: false });
|
||||
fs.writeFileSync('/tmp/app-snapshot.json', JSON.stringify(snap, null, 2));
|
||||
```
|
||||
|
||||
### 3. `send.ts` — Advanced Text Injection
|
||||
Electron apps often use complex rich-text editors (Monaco, Lexical, ProseMirror). Setting `.value` directly is ignored by React state.
|
||||
|
||||
**Best practice:** Use `document.execCommand('insertText')` to perfectly simulate real user input, fully piercing React state:
|
||||
```javascript
|
||||
const composer = document.querySelector('[contenteditable="true"]');
|
||||
composer.focus();
|
||||
document.execCommand('insertText', false, 'Hello');
|
||||
```
|
||||
Then submit with `await page.pressKey('Enter')`.
|
||||
|
||||
### 4. `read.ts` — Context Extraction
|
||||
Don't extract the entire page text. Use `dump.ts` output to find the real "conversation container":
|
||||
- Look for semantic selectors: `[role="log"]`, `[data-testid="conversation"]`, `[data-content-search-turn-key]`
|
||||
- Format output as Markdown — readable by both humans and LLMs
|
||||
|
||||
### 5. `new.ts` — Keyboard Shortcuts
|
||||
Many GUI actions respond to native shortcuts rather than button clicks:
|
||||
```typescript
|
||||
const isMac = process.platform === 'darwin';
|
||||
await page.pressKey(isMac ? 'Meta+N' : 'Control+N');
|
||||
await page.wait(1); // Wait for re-render
|
||||
```
|
||||
|
||||
## Environment Variable
|
||||
```bash
|
||||
export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9222"
|
||||
```
|
||||
|
||||
## Non-Electron Pattern (AppleScript)
|
||||
|
||||
For native macOS apps (WeChat, Feishu) that don't expose CDP:
|
||||
```typescript
|
||||
export const statusCommand = cli({
|
||||
site: 'myapp',
|
||||
strategy: Strategy.PUBLIC,
|
||||
browser: false, // No browser needed
|
||||
func: async (page: IPage | null) => {
|
||||
const output = execSync("osascript -e 'application \"MyApp\" is running'", { encoding: 'utf-8' }).trim();
|
||||
return [{ Status: output === 'true' ? 'Running' : 'Stopped' }];
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Core techniques:
|
||||
- **status**: `osascript -e 'application "AppName" is running'`
|
||||
- **send**: `pbcopy` → activate window → `Cmd+V` → `Enter`
|
||||
- **read**: `Cmd+A` → `Cmd+C` → `pbpaste`
|
||||
- **search**: Activate → `Cmd+F`/`Cmd+K` → `keystroke "query"`
|
||||
|
||||
## Pitfalls & Gotchas
|
||||
|
||||
1. **Port conflicts (EADDRINUSE)**: Only one app per port. Use unique ports: Codex=9222, ChatGPT=9224, Cursor=9226, ChatWise=9228, Notion=9230, Discord=9232
|
||||
2. **IPage abstraction**: OpenCLI wraps the browser page as `IPage` (`src/types.ts`). Use `page.pressKey()` and `page.evaluate()`, NOT direct DOM APIs
|
||||
3. **Timing**: Always add `await page.wait(0.5)` to `1.0` after DOM mutations. Returning too early disconnects prematurely
|
||||
4. **AppleScript requires Accessibility**: Terminal app must be granted permission in System Settings → Privacy & Security → Accessibility
|
||||
|
||||
## Port Assignment Table
|
||||
|
||||
| App | Port | Mode |
|
||||
|-----|------|------|
|
||||
| Codex | 9222 | CDP |
|
||||
| ChatGPT | 9224 | CDP / AppleScript |
|
||||
| Cursor | 9226 | CDP |
|
||||
| ChatWise | 9228 | CDP |
|
||||
| Notion | 9230 | CDP |
|
||||
| Discord App | 9232 | CDP |
|
||||
@@ -0,0 +1,72 @@
|
||||
# Remote Chrome
|
||||
|
||||
Run OpenCLI on a server or headless environment by connecting to a remote Chrome instance.
|
||||
|
||||
## Use Cases
|
||||
|
||||
- Running CLI commands on a remote server
|
||||
- CI/CD automation with headed browser
|
||||
- Shared team browser sessions
|
||||
|
||||
## Setup
|
||||
|
||||
### 1. Start Chrome on the Remote Machine
|
||||
|
||||
```bash
|
||||
# On the remote machine (or your Mac)
|
||||
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
|
||||
--remote-debugging-port=9222
|
||||
```
|
||||
|
||||
### 2. SSH Tunnel (If Needed)
|
||||
|
||||
If the remote Chrome is on a different machine, create an SSH tunnel:
|
||||
|
||||
```bash
|
||||
# On your local machine or server
|
||||
ssh -L 9222:127.0.0.1:9222 user@remote-host
|
||||
```
|
||||
|
||||
::: warning
|
||||
Use `127.0.0.1` instead of `localhost` in the SSH command to avoid IPv6 resolution issues that can cause timeouts.
|
||||
:::
|
||||
|
||||
### 3. Configure OpenCLI
|
||||
|
||||
```bash
|
||||
export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9222"
|
||||
```
|
||||
|
||||
### 4. Verify
|
||||
|
||||
```bash
|
||||
# Test the connection
|
||||
curl http://127.0.0.1:9222/json/version
|
||||
|
||||
# Run a diagnostic
|
||||
opencli doctor
|
||||
```
|
||||
|
||||
## CI/CD Integration
|
||||
|
||||
For CI/CD environments, use a real Chrome instance with `xvfb`:
|
||||
|
||||
::: v-pre
|
||||
```yaml
|
||||
steps:
|
||||
- uses: browser-actions/setup-chrome@latest
|
||||
id: setup-chrome
|
||||
- run: |
|
||||
xvfb-run --auto-servernum \
|
||||
${{ steps.setup-chrome.outputs.chrome-path }} \
|
||||
--remote-debugging-port=9222 &
|
||||
```
|
||||
:::
|
||||
|
||||
Set the browser executable path:
|
||||
::: v-pre
|
||||
```yaml
|
||||
env:
|
||||
OPENCLI_BROWSER_EXECUTABLE_PATH: ${{ steps.setup-chrome.outputs.chrome-path }}
|
||||
```
|
||||
:::
|
||||
@@ -0,0 +1,66 @@
|
||||
# AI Workflow
|
||||
|
||||
OpenCLI is designed with AI agents in mind. This guide covers the AI-native discovery and code generation tools.
|
||||
|
||||
## Quick Mode (One-Shot)
|
||||
|
||||
Generate a single command for a specific page URL — just a URL + one-line goal, 4 steps done:
|
||||
|
||||
```bash
|
||||
opencli generate https://example.com --goal "trending"
|
||||
```
|
||||
|
||||
This runs: explore → synthesize → register in one shot.
|
||||
|
||||
For the complete one-shot workflow details, see [CLI-ONESHOT.md](https://github.com/jackwener/opencli/blob/main/CLI-ONESHOT.md).
|
||||
|
||||
## Full Mode (Explorer Workflow)
|
||||
|
||||
### Step 1: Deep Explore
|
||||
|
||||
Discover APIs, infer capabilities, and detect framework:
|
||||
|
||||
```bash
|
||||
opencli explore https://example.com --site mysite
|
||||
```
|
||||
|
||||
Outputs to `.opencli/explore/<site>/`:
|
||||
- `manifest.json` — Site metadata
|
||||
- `endpoints.json` — Discovered API endpoints
|
||||
- `capabilities.json` — Inferred capabilities
|
||||
- `auth.json` — Authentication strategy details
|
||||
|
||||
### Step 2: Synthesize
|
||||
|
||||
Generate YAML adapters from explore artifacts:
|
||||
|
||||
```bash
|
||||
opencli synthesize mysite
|
||||
```
|
||||
|
||||
### Step 3: Strategy Cascade
|
||||
|
||||
Auto-probe authentication strategies: `PUBLIC → COOKIE → HEADER`:
|
||||
|
||||
```bash
|
||||
opencli cascade https://api.example.com/data
|
||||
```
|
||||
|
||||
### Step 4: Validate & Test
|
||||
|
||||
```bash
|
||||
opencli validate # Validate generated YAML
|
||||
opencli <site> <command> --limit 3 -f json # Test the command
|
||||
```
|
||||
|
||||
## 5-Tier Authentication Strategy
|
||||
|
||||
The explorer uses a decision tree to determine the best authentication approach:
|
||||
|
||||
1. **PUBLIC** — No auth, direct API call
|
||||
2. **COOKIE** — Reuse Chrome session cookies
|
||||
3. **HEADER** — Custom auth headers
|
||||
4. **BROWSER** — Full browser automation
|
||||
5. **CDP** — Chrome DevTools Protocol for Electron apps
|
||||
|
||||
For the complete browser exploration workflow and debugging guide, see [CLI-EXPLORER.md](https://github.com/jackwener/opencli/blob/main/CLI-EXPLORER.md).
|
||||
@@ -0,0 +1,90 @@
|
||||
# Architecture
|
||||
|
||||
OpenCLI is built on a **Dual-Engine Architecture** that supports both declarative YAML pipelines and programmatic TypeScript adapters.
|
||||
|
||||
## High-Level Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ opencli CLI │
|
||||
│ (Commander.js entry point) │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ Engine Layer │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │
|
||||
│ │ Registry │ │ Dynamic │ │ Output │ │
|
||||
│ │ (commands) │ │ Loader │ │ Formatter │ │
|
||||
│ └──────────────┘ └──────────────┘ └────────────┘ │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ Adapter Layer │
|
||||
│ ┌─────────────────┐ ┌──────────────────────────┐ │
|
||||
│ │ YAML Pipeline │ │ TypeScript Adapters │ │
|
||||
│ │ (declarative) │ │ (browser/desktop/AI) │ │
|
||||
│ └─────────────────┘ └──────────────────────────┘ │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ Connection Layer │
|
||||
│ ┌─────────────────┐ ┌──────────────────────────┐ │
|
||||
│ │ Browser Bridge │ │ CDP (Chrome DevTools) │ │
|
||||
│ │ (Extension+WS) │ │ (Electron apps) │ │
|
||||
│ └─────────────────┘ └──────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Core Modules
|
||||
|
||||
### Registry (`src/registry.ts`)
|
||||
Central command registry. All adapters register their commands via the `cli()` function with metadata: site, name, description, domain, strategy, args, columns.
|
||||
|
||||
### Engine (`src/engine.ts`)
|
||||
Command discovery and execution engine. Discovers commands from the registry, parses arguments, executes the appropriate adapter, and routes output through the formatter.
|
||||
|
||||
### Browser (`src/browser.ts`)
|
||||
Manages connections to Chrome via the Browser Bridge WebSocket daemon. Handles JSON-RPC messaging, tab management, and extension/standalone mode switching.
|
||||
|
||||
### Pipeline (`src/pipeline/`)
|
||||
The YAML pipeline engine. Processes declarative steps:
|
||||
- **fetch** — HTTP requests with cookie/header strategies
|
||||
- **map** — Data transformation with template expressions
|
||||
- **limit** — Result truncation
|
||||
- **filter** — Conditional filtering
|
||||
- **download** — Media download support
|
||||
|
||||
### Output (`src/output.ts`)
|
||||
Unified output formatting: `table`, `json`, `yaml`, `md`, `csv`.
|
||||
|
||||
## Authentication Strategies
|
||||
|
||||
OpenCLI uses a 3-tier authentication strategy:
|
||||
|
||||
| Strategy | How It Works | When to Use |
|
||||
|----------|-------------|-------------|
|
||||
| `public` | Direct HTTP fetch, no auth | Public APIs (HackerNews, BBC) |
|
||||
| `cookie` | Reuse Chrome cookies via Browser Bridge | Logged-in sites (Bilibili, Zhihu) |
|
||||
| `header` | Custom auth headers | API-key based services |
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── main.ts # Entry point
|
||||
├── engine.ts # Command execution engine
|
||||
├── registry.ts # Command registry
|
||||
├── browser.ts # Browser Bridge connection
|
||||
├── output.ts # Output formatting
|
||||
├── doctor.ts # Diagnostic tool
|
||||
├── pipeline/ # YAML pipeline engine
|
||||
│ ├── runner.ts
|
||||
│ ├── template.ts
|
||||
│ ├── transform.ts
|
||||
│ └── steps/
|
||||
│ ├── fetch.ts
|
||||
│ ├── map.ts
|
||||
│ ├── limit.ts
|
||||
│ ├── filter.ts
|
||||
│ └── download.ts
|
||||
└── clis/ # Site adapters
|
||||
├── twitter/
|
||||
├── reddit/
|
||||
├── bilibili/
|
||||
├── cursor/
|
||||
└── ...
|
||||
```
|
||||
@@ -0,0 +1,136 @@
|
||||
# Contributing
|
||||
|
||||
Thanks for your interest in contributing to OpenCLI.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# 1. Fork & clone
|
||||
git clone git@github.com:<your-username>/opencli.git
|
||||
cd opencli
|
||||
|
||||
# 2. Install dependencies
|
||||
npm install
|
||||
|
||||
# 3. Build
|
||||
npm run build
|
||||
|
||||
# 4. Run a few checks
|
||||
npx tsc --noEmit
|
||||
npx vitest run src/
|
||||
|
||||
# 5. Link globally (optional, for testing `opencli` command)
|
||||
npm link
|
||||
```
|
||||
|
||||
## Adding a New Site Adapter
|
||||
|
||||
This is the most common type of contribution. Start with YAML when possible, and use TypeScript only when you need browser-side logic or multi-step flows.
|
||||
|
||||
### YAML Adapter (Recommended for data-fetching commands)
|
||||
|
||||
Create a file like `src/clis/<site>/<command>.yaml`:
|
||||
|
||||
::: v-pre
|
||||
```yaml
|
||||
site: mysite
|
||||
name: trending
|
||||
description: Trending posts on MySite
|
||||
domain: www.mysite.com
|
||||
strategy: public # public | cookie | header
|
||||
browser: false # true if browser session is needed
|
||||
|
||||
args:
|
||||
limit:
|
||||
type: int
|
||||
default: 20
|
||||
description: Number of items
|
||||
|
||||
pipeline:
|
||||
- fetch:
|
||||
url: https://api.mysite.com/trending
|
||||
|
||||
- map:
|
||||
rank: ${{ index + 1 }}
|
||||
title: ${{ item.title }}
|
||||
score: ${{ item.score }}
|
||||
url: ${{ item.url }}
|
||||
|
||||
- limit: ${{ args.limit }}
|
||||
|
||||
columns: [rank, title, score, url]
|
||||
```
|
||||
:::
|
||||
|
||||
See [`hackernews/top.yaml`](https://github.com/jackwener/opencli/blob/main/src/clis/hackernews/top.yaml) for a real example.
|
||||
|
||||
### TypeScript Adapter (For complex browser interactions)
|
||||
|
||||
Create a file like `src/clis/<site>/<command>.ts`:
|
||||
|
||||
```typescript
|
||||
import { cli, Strategy } from '../../registry.js';
|
||||
|
||||
cli({
|
||||
site: 'mysite',
|
||||
name: 'search',
|
||||
description: 'Search MySite',
|
||||
domain: 'www.mysite.com',
|
||||
strategy: Strategy.COOKIE,
|
||||
args: [
|
||||
{ name: 'query', required: true, help: 'Search query' },
|
||||
{ name: 'limit', type: 'int', default: 10, help: 'Max results' },
|
||||
],
|
||||
columns: ['title', 'url', 'date'],
|
||||
|
||||
func: async (page, kwargs) => {
|
||||
const { query, limit = 10 } = kwargs;
|
||||
// ... browser automation logic
|
||||
return data.slice(0, Number(limit)).map((item: any) => ({
|
||||
title: item.title,
|
||||
url: item.url,
|
||||
date: item.created_at,
|
||||
}));
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Validate Your Adapter
|
||||
|
||||
```bash
|
||||
opencli validate # Validate YAML syntax and schema
|
||||
opencli <site> <command> --limit 3 -f json # Test your command
|
||||
opencli <site> <command> -v # Verbose mode for debugging
|
||||
```
|
||||
|
||||
## Code Style
|
||||
|
||||
- **TypeScript strict mode** — avoid `any` where possible.
|
||||
- **ES Modules** — use `.js` extensions in imports (TypeScript output).
|
||||
- **Naming**: `kebab-case` for files, `camelCase` for variables/functions, `PascalCase` for types/classes.
|
||||
- **No default exports** — use named exports.
|
||||
|
||||
## Commit Convention
|
||||
|
||||
We use [Conventional Commits](https://www.conventionalcommits.org/):
|
||||
|
||||
```
|
||||
feat(twitter): add thread command
|
||||
fix(browser): handle CDP timeout gracefully
|
||||
docs: update CONTRIBUTING.md
|
||||
test(reddit): add e2e test for save command
|
||||
chore: bump vitest to v4
|
||||
```
|
||||
|
||||
## Submitting a Pull Request
|
||||
|
||||
1. Create a feature branch: `git checkout -b feat/mysite-trending`
|
||||
2. Make your changes and add tests when relevant
|
||||
3. Run the checks:
|
||||
```bash
|
||||
npx tsc --noEmit # Type check
|
||||
npx vitest run src/ # Unit tests
|
||||
opencli validate # YAML validation (if applicable)
|
||||
```
|
||||
4. Commit using conventional commit format
|
||||
5. Push and open a PR
|
||||
@@ -0,0 +1,237 @@
|
||||
# Testing Guide
|
||||
|
||||
> 面向开发者和 AI Agent 的测试参考手册。
|
||||
|
||||
## 目录
|
||||
|
||||
- [测试架构](#测试架构)
|
||||
- [当前覆盖范围](#当前覆盖范围)
|
||||
- [本地运行测试](#本地运行测试)
|
||||
- [如何添加新测试](#如何添加新测试)
|
||||
- [CI/CD 流水线](#cicd-流水线)
|
||||
- [浏览器模式](#浏览器模式)
|
||||
- [站点兼容性](#站点兼容性)
|
||||
|
||||
---
|
||||
|
||||
## 测试架构
|
||||
|
||||
测试分为三层,全部使用 **vitest** 运行:
|
||||
|
||||
```
|
||||
tests/
|
||||
├── e2e/ # E2E 集成测试(子进程运行真实 CLI)
|
||||
│ ├── helpers.ts # runCli() 共享工具
|
||||
│ ├── public-commands.test.ts # 公开 API 命令(无需浏览器)
|
||||
│ ├── browser-public.test.ts # 浏览器命令(公开数据)
|
||||
│ ├── browser-auth.test.ts # 需登录命令(graceful failure 测试)
|
||||
│ ├── management.test.ts # 管理命令(list, validate, verify, help)
|
||||
│ └── output-formats.test.ts # 输出格式(json/yaml/csv/md)
|
||||
├── smoke/ # 烟雾测试(仅定时 / 手动触发)
|
||||
│ └── api-health.test.ts # 外部 API 可用性检测
|
||||
src/
|
||||
├── *.test.ts # 单元测试(已有 8 个)
|
||||
```
|
||||
|
||||
| 层 | 位置 | 运行方式 | 用途 |
|
||||
|---|---|---|---|
|
||||
| 单元测试 | `src/**/*.test.ts` | `npx vitest run src/` | 内部模块逻辑 |
|
||||
| E2E 测试 | `tests/e2e/*.test.ts` | `npx vitest run tests/e2e/` | 真实 CLI 命令执行 |
|
||||
| 烟雾测试 | `tests/smoke/*.test.ts` | `npx vitest run tests/smoke/` | 外部 API 健康 |
|
||||
|
||||
---
|
||||
|
||||
## 当前覆盖范围
|
||||
|
||||
### 单元测试(8 个文件)
|
||||
|
||||
| 文件 | 覆盖内容 |
|
||||
|---|---|
|
||||
| `browser.test.ts` | JSON-RPC、tab 管理、extension/standalone 模式切换 |
|
||||
| `engine.test.ts` | 命令发现与执行 |
|
||||
| `registry.test.ts` | 命令注册与策略分配 |
|
||||
| `output.test.ts` | 输出格式渲染 |
|
||||
| `doctor.test.ts` | Token 诊断 |
|
||||
| `coupang.test.ts` | 数据归一化 |
|
||||
| `pipeline/template.test.ts` | 模板表达式求值 |
|
||||
| `pipeline/transform.test.ts` | 数据变换步骤 |
|
||||
|
||||
### E2E 测试(~52 个用例)
|
||||
|
||||
| 文件 | 覆盖站点/功能 | 测试数 |
|
||||
|---|---|---|
|
||||
| `public-commands.test.ts` | hackernews/top, v2ex/hot, v2ex/latest, v2ex/topic | 5 |
|
||||
| `browser-public.test.ts` | bbc, bilibili×3, weibo, zhihu×2, reddit×2, twitter, xueqiu×2, reuters, youtube, smzdm, boss, ctrip, coupang, xiaohongshu, yahoo-finance, v2ex/daily | 21 |
|
||||
| `browser-auth.test.ts` | bilibili/me,dynamic,favorite,history,following + twitter/bookmarks,timeline,notifications + v2ex/me,notifications + xueqiu/feed,watchlist + xiaohongshu/feed,notifications | 14 |
|
||||
| `management.test.ts` | list×5 格式, validate×3 级别, verify, --version, --help, unknown cmd | 12 |
|
||||
| `output-formats.test.ts` | json, yaml, csv, md 格式验证 | 5 |
|
||||
|
||||
### 烟雾测试
|
||||
|
||||
公开 API 可用性(hackernews, v2ex×2, v2ex/topic)+ 全站点注册完整性检查。
|
||||
|
||||
---
|
||||
|
||||
## 本地运行测试
|
||||
|
||||
### 前置条件
|
||||
|
||||
```bash
|
||||
npm ci # 安装依赖
|
||||
npm run build # 编译(E2E 测试需要 dist/main.js)
|
||||
```
|
||||
|
||||
### 运行命令
|
||||
|
||||
```bash
|
||||
# 全部单元测试
|
||||
npx vitest run src/
|
||||
|
||||
# 全部 E2E 测试(会真实调用外部 API)
|
||||
npx vitest run tests/e2e/
|
||||
|
||||
# 单个测试文件
|
||||
npx vitest run tests/e2e/management.test.ts
|
||||
|
||||
# 全部测试(单元 + E2E)
|
||||
npx vitest run
|
||||
|
||||
# 烟雾测试
|
||||
npx vitest run tests/smoke/
|
||||
|
||||
# watch 模式(开发时推荐)
|
||||
npx vitest src/
|
||||
```
|
||||
|
||||
### 浏览器命令本地测试须知
|
||||
|
||||
- opencli 通过 Browser Bridge 扩展连接已运行的 Chrome 浏览器
|
||||
- `browser-public.test.ts` 使用 `tryBrowserCommand()`,站点反爬导致空数据时 warn + pass
|
||||
- `browser-auth.test.ts` 验证 **graceful failure**(不 crash 不 hang 即通过)
|
||||
- 如需测试完整登录态,保持 Chrome 登录态并安装 Browser Bridge 扩展,手动跑对应测试
|
||||
|
||||
---
|
||||
|
||||
## 如何添加新测试
|
||||
|
||||
### 新增 YAML Adapter(如 `src/clis/producthunt/trending.yaml`)
|
||||
|
||||
1. **无需额外操作**:`validate` 测试会自动覆盖 YAML 结构验证
|
||||
2. 根据 adapter 类型,在对应文件加一个 `it()` block:
|
||||
|
||||
```typescript
|
||||
// 如果 browser: false(公开 API)→ tests/e2e/public-commands.test.ts
|
||||
it('producthunt trending returns data', async () => {
|
||||
const { stdout, code } = await runCli(['producthunt', 'trending', '--limit', '3', '-f', 'json']);
|
||||
expect(code).toBe(0);
|
||||
const data = parseJsonOutput(stdout);
|
||||
expect(Array.isArray(data)).toBe(true);
|
||||
expect(data.length).toBeGreaterThanOrEqual(1);
|
||||
expect(data[0]).toHaveProperty('title');
|
||||
}, 30_000);
|
||||
```
|
||||
|
||||
```typescript
|
||||
// 如果 browser: true 但可公开访问 → tests/e2e/browser-public.test.ts
|
||||
it('producthunt trending returns data', async () => {
|
||||
const data = await tryBrowserCommand(['producthunt', 'trending', '--limit', '3', '-f', 'json']);
|
||||
expectDataOrSkip(data, 'producthunt trending');
|
||||
}, 60_000);
|
||||
```
|
||||
|
||||
```typescript
|
||||
// 如果 browser: true 且需登录 → tests/e2e/browser-auth.test.ts
|
||||
it('producthunt me fails gracefully without login', async () => {
|
||||
await expectGracefulAuthFailure(['producthunt', 'me', '-f', 'json'], 'producthunt me');
|
||||
}, 60_000);
|
||||
```
|
||||
|
||||
### 新增管理命令(如 `opencli export`)
|
||||
|
||||
在 `tests/e2e/management.test.ts` 添加测试。
|
||||
|
||||
### 新增内部模块
|
||||
|
||||
在 `src/` 下对应位置创建 `*.test.ts`。
|
||||
|
||||
### 决策流程图
|
||||
|
||||
```
|
||||
新增功能 → 是内部模块? → 是 → src/ 下加 *.test.ts
|
||||
↓ 否
|
||||
是 CLI 命令? → browser: false? → tests/e2e/public-commands.test.ts
|
||||
↓ true
|
||||
公开数据? → tests/e2e/browser-public.test.ts
|
||||
↓ 需登录
|
||||
tests/e2e/browser-auth.test.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CI/CD 流水线
|
||||
|
||||
### ci.yml(主流水线)
|
||||
|
||||
| Job | 触发条件 | 内容 |
|
||||
|---|---|---|
|
||||
| **build** | push/PR to main,dev | typecheck + build |
|
||||
| **unit-test** | push/PR to main,dev | 单元测试,2 shard 并行 |
|
||||
| **smoke-test** | 每周一 08:00 UTC / 手动 | xvfb + real Chrome,外部 API 健康检查 |
|
||||
|
||||
### e2e-headed.yml(E2E 测试)
|
||||
|
||||
| Job | 触发条件 | 内容 |
|
||||
|---|---|---|
|
||||
| **e2e-headed** | push/PR to main,dev | xvfb + real Chrome,全部 E2E 测试 |
|
||||
|
||||
E2E 使用 `browser-actions/setup-chrome` 安装真实 Chrome,配合 `xvfb-run` 提供虚拟显示器,以 headed 模式运行浏览器。
|
||||
|
||||
### Sharding
|
||||
|
||||
单元测试使用 vitest 内置 shard:
|
||||
|
||||
::: v-pre
|
||||
```yaml
|
||||
strategy:
|
||||
matrix:
|
||||
shard: [1, 2]
|
||||
steps:
|
||||
- run: npx vitest run src/ --shard=${{ matrix.shard }}/2
|
||||
```
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 浏览器模式
|
||||
|
||||
opencli 通过 Browser Bridge 扩展连接浏览器:
|
||||
|
||||
| 条件 | 模式 | 使用场景 |
|
||||
|---|---|---|
|
||||
| 扩展已安装 | Extension 模式 | 本地用户,连接已登录的 Chrome |
|
||||
| 扩展未安装 | CLI 报错提示安装 | 需要安装 Browser Bridge 扩展 |
|
||||
|
||||
CI 中使用 `OPENCLI_BROWSER_EXECUTABLE_PATH` 指定真实 Chrome 路径:
|
||||
|
||||
::: v-pre
|
||||
```yaml
|
||||
env:
|
||||
OPENCLI_BROWSER_EXECUTABLE_PATH: ${{ steps.setup-chrome.outputs.chrome-path }}
|
||||
```
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 站点兼容性
|
||||
|
||||
在 GitHub Actions 美国 runner 上,部分站点因地域限制或登录要求返回空数据。E2E 测试对这些站点使用 warn + pass 策略,不影响 CI 绿灯。
|
||||
|
||||
| 站点 | CI 状态 | 限制原因 |
|
||||
|---|---|---|
|
||||
| hackernews, bbc, v2ex | ✅ 返回数据 | 无限制 |
|
||||
| yahoo-finance | ✅ 返回数据 | 无限制 |
|
||||
| bilibili, zhihu, weibo, xiaohongshu | ⚠️ 空数据 | 地域限制(中国站点) |
|
||||
| reddit, twitter, youtube | ⚠️ 空数据 | 需登录或 cookie |
|
||||
| smzdm, boss, ctrip, coupang, xueqiu | ⚠️ 空数据 | 地域限制 / 需登录 |
|
||||
|
||||
> 使用 self-hosted runner(国内服务器)可解决地域限制问题。
|
||||
@@ -0,0 +1,87 @@
|
||||
# TypeScript Adapter Guide
|
||||
|
||||
Use TypeScript adapters when you need browser-side logic, multi-step flows, DOM manipulation, or complex data extraction that goes beyond simple API fetching.
|
||||
|
||||
## Basic Structure
|
||||
|
||||
```typescript
|
||||
import { cli, Strategy } from '../../registry.js';
|
||||
|
||||
cli({
|
||||
site: 'mysite',
|
||||
name: 'search',
|
||||
description: 'Search MySite',
|
||||
domain: 'www.mysite.com',
|
||||
strategy: Strategy.COOKIE, // PUBLIC | COOKIE | HEADER
|
||||
args: [
|
||||
{ name: 'query', required: true, help: 'Search query' },
|
||||
{ name: 'limit', type: 'int', default: 10, help: 'Max results' },
|
||||
],
|
||||
columns: ['title', 'url', 'date'],
|
||||
|
||||
func: async (page, kwargs) => {
|
||||
const { query, limit = 10 } = kwargs;
|
||||
|
||||
// Navigate and extract data
|
||||
await page.goto('https://www.mysite.com');
|
||||
|
||||
const data = await page.evaluate(`
|
||||
(async () => {
|
||||
const res = await fetch('/api/search?q=${encodeURIComponent(String(query))}', {
|
||||
credentials: 'include'
|
||||
});
|
||||
return (await res.json()).results;
|
||||
})()
|
||||
`);
|
||||
|
||||
return data.slice(0, Number(limit)).map((item: any) => ({
|
||||
title: item.title,
|
||||
url: item.url,
|
||||
date: item.created_at,
|
||||
}));
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Strategy Types
|
||||
|
||||
| Strategy | Constant | Use Case |
|
||||
|----------|----------|----------|
|
||||
| Public | `Strategy.PUBLIC` | No auth needed |
|
||||
| Cookie | `Strategy.COOKIE` | Browser session cookies |
|
||||
| Header | `Strategy.HEADER` | Custom headers/tokens |
|
||||
|
||||
## The `page` Object
|
||||
|
||||
The `page` parameter provides browser interaction methods:
|
||||
|
||||
- `page.goto(url)` — Navigate to a URL
|
||||
- `page.evaluate(script)` — Execute JavaScript in the page context
|
||||
- `page.waitForSelector(selector)` — Wait for an element
|
||||
- `page.click(selector)` — Click an element
|
||||
- `page.type(selector, text)` — Type text into an input
|
||||
|
||||
## The `kwargs` Object
|
||||
|
||||
Contains parsed CLI arguments as key-value pairs. Always destructure with defaults:
|
||||
|
||||
```typescript
|
||||
const { query, limit = 10, format = 'json' } = kwargs;
|
||||
```
|
||||
|
||||
## AI-Assisted Development
|
||||
|
||||
Use the AI workflow tools to accelerate adapter creation:
|
||||
|
||||
```bash
|
||||
# Discover APIs and page structure
|
||||
opencli explore https://example.com --site mysite
|
||||
|
||||
# Auto-generate adapter from explore artifacts
|
||||
opencli synthesize mysite
|
||||
|
||||
# One-shot: explore → synthesize → register
|
||||
opencli generate https://example.com --goal "trending"
|
||||
```
|
||||
|
||||
See [AI Workflow](/developer/ai-workflow) for the complete guide.
|
||||
@@ -0,0 +1,108 @@
|
||||
# YAML Adapter Guide
|
||||
|
||||
YAML adapters are the recommended way to add new commands when the site offers a straightforward API. They use a declarative pipeline approach — no TypeScript required.
|
||||
|
||||
## Basic Structure
|
||||
|
||||
::: v-pre
|
||||
```yaml
|
||||
site: mysite # Site identifier
|
||||
name: trending # Command name (opencli mysite trending)
|
||||
description: ... # Help text
|
||||
domain: www.mysite.com
|
||||
strategy: public # public | cookie | header
|
||||
browser: false # true if browser session is needed
|
||||
|
||||
args: # CLI arguments
|
||||
limit:
|
||||
type: int
|
||||
default: 20
|
||||
description: Number of items
|
||||
|
||||
pipeline: # Data processing steps
|
||||
- fetch:
|
||||
url: https://api.mysite.com/trending
|
||||
|
||||
- map:
|
||||
rank: ${{ index + 1 }}
|
||||
title: ${{ item.title }}
|
||||
|
||||
- limit: ${{ args.limit }}
|
||||
|
||||
columns: [rank, title, score, url]
|
||||
```
|
||||
:::
|
||||
|
||||
## Pipeline Steps
|
||||
|
||||
### `fetch`
|
||||
Fetch data from a URL. Supports template expressions for dynamic URLs.
|
||||
|
||||
::: v-pre
|
||||
```yaml
|
||||
- fetch:
|
||||
url: https://api.example.com/search?q=${{ args.query }}
|
||||
headers:
|
||||
Accept: application/json
|
||||
```
|
||||
:::
|
||||
|
||||
### `map`
|
||||
|
||||
::: v-pre
|
||||
Transform each item in the result array. Use `${{ item.xxx }}` for field access and `${{ index }}` for position.
|
||||
|
||||
```yaml
|
||||
- map:
|
||||
rank: ${{ index + 1 }}
|
||||
title: ${{ item.title }}
|
||||
url: https://example.com${{ item.path }}
|
||||
```
|
||||
:::
|
||||
|
||||
### `limit`
|
||||
Truncate results to N items.
|
||||
|
||||
::: v-pre
|
||||
```yaml
|
||||
- limit: ${{ args.limit }}
|
||||
```
|
||||
:::
|
||||
|
||||
### `filter`
|
||||
Filter items by condition.
|
||||
|
||||
::: v-pre
|
||||
```yaml
|
||||
- filter: ${{ item.score > 100 }}
|
||||
```
|
||||
:::
|
||||
|
||||
### `download`
|
||||
Download media files.
|
||||
|
||||
::: v-pre
|
||||
```yaml
|
||||
- download:
|
||||
url: ${{ item.imageUrl }}
|
||||
dir: ./downloads
|
||||
filename: ${{ item.title | sanitize }}.jpg
|
||||
```
|
||||
:::
|
||||
|
||||
## Template Expressions
|
||||
|
||||
::: v-pre
|
||||
Use `${{ ... }}` for dynamic values:
|
||||
|
||||
| Expression | Description |
|
||||
|-----------|-------------|
|
||||
| `${{ args.limit }}` | CLI argument |
|
||||
| `${{ item.title }}` | Current item field |
|
||||
| `${{ index }}` | Current index (0-based) |
|
||||
| `${{ item.x \| sanitize }}` | Pipe filters |
|
||||
:::
|
||||
|
||||
## Real Example
|
||||
|
||||
See [`src/clis/hackernews/top.yaml`](https://github.com/jackwener/opencli/blob/main/src/clis/hackernews/top.yaml).
|
||||
@@ -0,0 +1,38 @@
|
||||
# Browser Bridge Setup
|
||||
|
||||
> **⚠️ Important**: Browser commands reuse your Chrome login session. You must be logged into the target website in Chrome before running commands.
|
||||
|
||||
OpenCLI connects to your browser through a lightweight **Browser Bridge** Chrome Extension + micro-daemon (zero config, auto-start).
|
||||
|
||||
## Extension Installation
|
||||
|
||||
### Method 1: Download Pre-built Release (Recommended)
|
||||
|
||||
1. Go to the GitHub [Releases page](https://github.com/jackwener/opencli/releases) and download the latest `opencli-extension.zip` or `opencli-extension.crx`.
|
||||
2. Open `chrome://extensions` and enable **Developer mode** (top-right toggle).
|
||||
3. Drag and drop the `.crx` file or the unzipped folder into the extensions page.
|
||||
|
||||
### Method 2: Load Unpacked Source (For Developers)
|
||||
|
||||
1. Open `chrome://extensions` and enable **Developer mode**.
|
||||
2. Click **Load unpacked** and select the `extension/` directory from the repository.
|
||||
|
||||
## Verification
|
||||
|
||||
That's it! The daemon auto-starts when you run any browser command. No tokens, no manual configuration.
|
||||
|
||||
```bash
|
||||
opencli doctor # Check extension + daemon connectivity
|
||||
opencli doctor --live # Also test live browser commands
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
```
|
||||
┌─────────────┐ WebSocket ┌──────────────┐ Chrome API ┌─────────┐
|
||||
│ opencli │ ◄──────────────► │ micro-daemon │ ◄──────────────► │ Chrome │
|
||||
│ (Node.js) │ localhost:19825 │ (auto-start) │ Extension │ Browser │
|
||||
└─────────────┘ └──────────────┘ └─────────┘
|
||||
```
|
||||
|
||||
The daemon manages the WebSocket connection between your CLI commands and the Chrome extension. The extension executes JavaScript in the context of web pages, with access to the logged-in session.
|
||||
@@ -0,0 +1,56 @@
|
||||
# Getting Started
|
||||
|
||||
> **Make any website or Electron App your CLI.**
|
||||
> Zero risk · Reuse Chrome login · AI-powered discovery · Browser + Desktop automation
|
||||
|
||||
[](https://www.npmjs.com/package/@jackwener/opencli)
|
||||
[](https://nodejs.org)
|
||||
[](https://github.com/jackwener/opencli/blob/main/LICENSE)
|
||||
|
||||
OpenCLI turns **any website** or **Electron app** into a command-line interface — Bilibili, Zhihu, 小红书, Twitter/X, Reddit, YouTube, Antigravity, and [many more](/adapters/) — powered by browser session reuse and AI-native discovery.
|
||||
|
||||
## Highlights
|
||||
|
||||
- **CLI All Electron** — CLI-ify apps like Antigravity Ultra! Now AI can control itself natively.
|
||||
- **Account-safe** — Reuses Chrome's logged-in state; your credentials never leave the browser.
|
||||
- **AI Agent ready** — `explore` discovers APIs, `synthesize` generates adapters, `cascade` finds auth strategies.
|
||||
- **Self-healing setup** — `opencli setup` verifies Browser Bridge connectivity; `opencli doctor` diagnoses daemon, extension, and live browser connectivity.
|
||||
- **Dynamic Loader** — Simply drop `.ts` or `.yaml` adapters into the `clis/` folder for auto-registration.
|
||||
- **Dual-Engine Architecture** — Supports both YAML declarative data pipelines and robust browser runtime TypeScript injections.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Install via npm
|
||||
|
||||
```bash
|
||||
npm install -g @jackwener/opencli
|
||||
```
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```bash
|
||||
opencli list # See all commands
|
||||
opencli hackernews top --limit 5 # Public API, no browser
|
||||
opencli bilibili hot --limit 5 # Browser command
|
||||
opencli zhihu hot -f json # JSON output
|
||||
```
|
||||
|
||||
### Output Formats
|
||||
|
||||
All built-in commands support `--format` / `-f`:
|
||||
|
||||
```bash
|
||||
opencli bilibili hot -f table # Default: rich terminal table
|
||||
opencli bilibili hot -f json # JSON (pipe to jq or LLMs)
|
||||
opencli bilibili hot -f yaml # YAML (human-readable)
|
||||
opencli bilibili hot -f md # Markdown
|
||||
opencli bilibili hot -f csv # CSV
|
||||
opencli bilibili hot -v # Verbose: show pipeline debug
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Installation details](/guide/installation)
|
||||
- [Browser Bridge setup](/guide/browser-bridge)
|
||||
- [All available adapters](/adapters/)
|
||||
- [For developers / AI agents](/developer/contributing)
|
||||
@@ -0,0 +1,37 @@
|
||||
# Installation
|
||||
|
||||
## Requirements
|
||||
|
||||
- **Node.js**: >= 20.0.0
|
||||
- **Chrome** running and logged into the target site (for browser commands)
|
||||
|
||||
## Install via npm (Recommended)
|
||||
|
||||
```bash
|
||||
npm install -g @jackwener/opencli
|
||||
```
|
||||
|
||||
## Install from Source
|
||||
|
||||
```bash
|
||||
git clone git@github.com:jackwener/opencli.git
|
||||
cd opencli
|
||||
npm install
|
||||
npm run build
|
||||
npm link # Link binary globally
|
||||
opencli list # Now you can use it anywhere!
|
||||
```
|
||||
|
||||
## Update
|
||||
|
||||
```bash
|
||||
npm install -g @jackwener/opencli@latest
|
||||
```
|
||||
|
||||
## Verify Installation
|
||||
|
||||
```bash
|
||||
opencli --version # Check version
|
||||
opencli list # List all commands
|
||||
opencli doctor # Diagnose connectivity
|
||||
```
|
||||
@@ -0,0 +1,56 @@
|
||||
# Troubleshooting
|
||||
|
||||
## Common Issues
|
||||
|
||||
### "Extension not connected"
|
||||
|
||||
- Ensure the opencli Browser Bridge extension is installed and **enabled** in `chrome://extensions`.
|
||||
- Run `opencli doctor` to diagnose connectivity.
|
||||
|
||||
### Empty data or 'Unauthorized' error
|
||||
|
||||
- Your login session in Chrome might have expired. Open a normal Chrome tab, navigate to the target site, and log in or refresh the page.
|
||||
- Some sites have geographic restrictions (e.g., Bilibili, Zhihu from outside China).
|
||||
|
||||
### Node API errors
|
||||
|
||||
- Make sure you are using **Node.js >= 20**. Some dependencies require modern Node APIs.
|
||||
- Run `node --version` to verify.
|
||||
|
||||
### Daemon issues
|
||||
|
||||
```bash
|
||||
# Check daemon status
|
||||
curl localhost:19825/status
|
||||
|
||||
# View extension logs
|
||||
curl localhost:19825/logs
|
||||
|
||||
# Kill and restart daemon
|
||||
pkill -f opencli-daemon
|
||||
opencli doctor
|
||||
```
|
||||
|
||||
### Desktop adapter connection issues
|
||||
|
||||
For Electron/CDP-based adapters (Cursor, Codex, etc.):
|
||||
|
||||
1. Make sure the app is launched with `--remote-debugging-port=XXXX`
|
||||
2. Verify the endpoint is set: `echo $OPENCLI_CDP_ENDPOINT`
|
||||
3. Test the endpoint: `curl http://127.0.0.1:XXXX/json/version`
|
||||
|
||||
### Build errors
|
||||
|
||||
```bash
|
||||
# Clean rebuild
|
||||
rm -rf dist/
|
||||
npm run build
|
||||
|
||||
# Type check
|
||||
npx tsc --noEmit
|
||||
```
|
||||
|
||||
## Getting Help
|
||||
|
||||
- [GitHub Issues](https://github.com/jackwener/opencli/issues) — Bug reports and feature requests
|
||||
- Run `opencli doctor --live` for comprehensive diagnostics
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
layout: home
|
||||
|
||||
hero:
|
||||
name: OpenCLI
|
||||
text: Make any website or Electron App your CLI
|
||||
tagline: Zero risk · Reuse Chrome login · AI-powered discovery · Browser + Desktop automation
|
||||
actions:
|
||||
- theme: brand
|
||||
text: Get Started
|
||||
link: /guide/getting-started
|
||||
- theme: alt
|
||||
text: View on GitHub
|
||||
link: https://github.com/jackwener/opencli
|
||||
|
||||
features:
|
||||
- icon: 🖥️
|
||||
title: CLI All Electron
|
||||
details: Turn ANY Electron application into a CLI tool — Cursor, Codex, Antigravity, ChatGPT, Notion, and more. AI can control itself natively.
|
||||
- icon: 🔐
|
||||
title: Account Safe
|
||||
details: Reuses Chrome's logged-in state. Your credentials never leave the browser — no tokens, no exposed passwords.
|
||||
- icon: 🤖
|
||||
title: AI Agent Ready
|
||||
details: "explore discovers APIs, synthesize generates adapters, cascade finds auth strategies. Built for AI-first workflows."
|
||||
- icon: ⚡
|
||||
title: Dual-Engine Architecture
|
||||
details: Supports both YAML declarative data pipelines and robust browser runtime TypeScript injections for maximum flexibility.
|
||||
- icon: 🔧
|
||||
title: Self-Healing Setup
|
||||
details: "opencli setup verifies Browser Bridge connectivity. opencli doctor diagnoses daemon, extension, and live browser."
|
||||
- icon: 📦
|
||||
title: Dynamic Loader
|
||||
details: Simply drop .ts or .yaml adapters into the clis/ folder for auto-registration. Zero boilerplate.
|
||||
---
|
||||
@@ -0,0 +1,5 @@
|
||||
# 所有适配器
|
||||
|
||||
运行 `opencli list` 查看完整命令列表。
|
||||
|
||||
详细文档请参考 [英文版本](/adapters/)。
|
||||
@@ -0,0 +1,3 @@
|
||||
# Chrome DevTools Protocol
|
||||
|
||||
详细文档请参考 [英文版本](/advanced/cdp)。
|
||||
@@ -0,0 +1,24 @@
|
||||
# 贡献指南
|
||||
|
||||
详细贡献指南请参考 [英文版本](/developer/contributing)。
|
||||
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
git clone git@github.com:<your-username>/opencli.git
|
||||
cd opencli
|
||||
npm install
|
||||
npm run build
|
||||
npx tsc --noEmit
|
||||
npx vitest run src/
|
||||
```
|
||||
|
||||
## 提交规范
|
||||
|
||||
使用 [Conventional Commits](https://www.conventionalcommits.org/):
|
||||
|
||||
```
|
||||
feat(twitter): add thread command
|
||||
fix(browser): handle CDP timeout gracefully
|
||||
docs: update CONTRIBUTING.md
|
||||
```
|
||||
@@ -0,0 +1,25 @@
|
||||
# Browser Bridge 设置
|
||||
|
||||
> **⚠️ 重要**: 浏览器命令复用你的 Chrome 登录会话。运行命令前必须在 Chrome 中登录目标网站。
|
||||
|
||||
OpenCLI 通过轻量级 **Browser Bridge** Chrome 扩展 + 微守护进程连接浏览器(零配置,自动启动)。
|
||||
|
||||
## 扩展安装
|
||||
|
||||
### 方法 1:下载预构建版本(推荐)
|
||||
|
||||
1. 前往 GitHub [Releases 页面](https://github.com/jackwener/opencli/releases) 下载最新的 `opencli-extension.zip` 或 `opencli-extension.crx`。
|
||||
2. 打开 `chrome://extensions`,启用**开发者模式**。
|
||||
3. 拖放 `.crx` 文件或解压后的文件夹到扩展页面。
|
||||
|
||||
### 方法 2:加载源码(开发者)
|
||||
|
||||
1. 打开 `chrome://extensions`,启用**开发者模式**。
|
||||
2. 点击**加载已解压的扩展程序**,选择仓库中的 `extension/` 目录。
|
||||
|
||||
## 验证
|
||||
|
||||
```bash
|
||||
opencli doctor # 检查扩展 + 守护进程连接
|
||||
opencli doctor --live # 同时测试实时浏览器命令
|
||||
```
|
||||
@@ -0,0 +1,40 @@
|
||||
# 快速开始
|
||||
|
||||
> **让任何网站或 Electron 应用成为你的 CLI。**
|
||||
> 零风险 · 复用 Chrome 登录态 · AI 驱动发现 · 浏览器 + 桌面自动化
|
||||
|
||||
OpenCLI 将**任何网站**或 **Electron 应用**变成命令行界面 — Bilibili、知乎、小红书、Twitter/X、Reddit、YouTube、Antigravity 等 — 基于浏览器会话复用和 AI 原生发现。
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
npm install -g @jackwener/opencli
|
||||
```
|
||||
|
||||
## 基本使用
|
||||
|
||||
```bash
|
||||
opencli list # 查看所有命令
|
||||
opencli hackernews top --limit 5 # 公开 API,无需浏览器
|
||||
opencli bilibili hot --limit 5 # 浏览器命令
|
||||
opencli zhihu hot -f json # JSON 输出
|
||||
```
|
||||
|
||||
## 输出格式
|
||||
|
||||
所有命令支持 `--format` / `-f`:
|
||||
|
||||
```bash
|
||||
opencli bilibili hot -f table # 默认:终端表格
|
||||
opencli bilibili hot -f json # JSON
|
||||
opencli bilibili hot -f yaml # YAML
|
||||
opencli bilibili hot -f md # Markdown
|
||||
opencli bilibili hot -f csv # CSV
|
||||
```
|
||||
|
||||
## 下一步
|
||||
|
||||
- [安装详情](/zh/guide/installation)
|
||||
- [Browser Bridge 设置](/zh/guide/browser-bridge)
|
||||
- [所有适配器](/zh/adapters/)
|
||||
- [开发者指南](/zh/developer/contributing)
|
||||
@@ -0,0 +1,37 @@
|
||||
# 安装
|
||||
|
||||
## 系统要求
|
||||
|
||||
- **Node.js**: >= 20.0.0
|
||||
- **Chrome** 已运行并登录目标网站(浏览器命令需要)
|
||||
|
||||
## 通过 npm 安装(推荐)
|
||||
|
||||
```bash
|
||||
npm install -g @jackwener/opencli
|
||||
```
|
||||
|
||||
## 从源码安装
|
||||
|
||||
```bash
|
||||
git clone git@github.com:jackwener/opencli.git
|
||||
cd opencli
|
||||
npm install
|
||||
npm run build
|
||||
npm link
|
||||
opencli list
|
||||
```
|
||||
|
||||
## 更新
|
||||
|
||||
```bash
|
||||
npm install -g @jackwener/opencli@latest
|
||||
```
|
||||
|
||||
## 验证安装
|
||||
|
||||
```bash
|
||||
opencli --version
|
||||
opencli list
|
||||
opencli doctor
|
||||
```
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
layout: home
|
||||
|
||||
hero:
|
||||
name: OpenCLI
|
||||
text: 让任何网站或 Electron 应用成为你的 CLI
|
||||
tagline: 零风险 · 复用 Chrome 登录态 · AI 驱动发现 · 浏览器 + 桌面自动化
|
||||
actions:
|
||||
- theme: brand
|
||||
text: 快速开始
|
||||
link: /zh/guide/getting-started
|
||||
- theme: alt
|
||||
text: 在 GitHub 查看
|
||||
link: https://github.com/jackwener/opencli
|
||||
|
||||
features:
|
||||
- icon: 🖥️
|
||||
title: CLI 所有 Electron 应用
|
||||
details: 将任何 Electron 应用变成 CLI 工具 — Cursor、Codex、Antigravity、ChatGPT、Notion 等。AI 可以原生控制自身。
|
||||
- icon: 🔐
|
||||
title: 账号安全
|
||||
details: 复用 Chrome 登录态,凭证永远不会离开浏览器 — 无 token,无密码泄露。
|
||||
- icon: 🤖
|
||||
title: AI Agent 就绪
|
||||
details: explore 发现 API,synthesize 生成适配器,cascade 查找认证策略。为 AI 优先工作流而生。
|
||||
- icon: ⚡
|
||||
title: 双引擎架构
|
||||
details: 同时支持 YAML 声明式数据管道和强大的浏览器运行时 TypeScript 注入。
|
||||
---
|
||||
Generated
+2402
-3
File diff suppressed because it is too large
Load Diff
+6
-2
@@ -26,7 +26,10 @@
|
||||
"prepublishOnly": "npm run build",
|
||||
"test": "vitest run",
|
||||
"test:site": "node scripts/test-site.mjs",
|
||||
"test:watch": "vitest"
|
||||
"test:watch": "vitest",
|
||||
"docs:dev": "vitepress dev docs",
|
||||
"docs:build": "vitepress build docs",
|
||||
"docs:preview": "vitepress preview docs"
|
||||
},
|
||||
"keywords": [
|
||||
"cli",
|
||||
@@ -49,10 +52,11 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/ws": "^8.5.13",
|
||||
"@types/node": "^22.13.10",
|
||||
"@types/ws": "^8.5.13",
|
||||
"tsx": "^4.19.3",
|
||||
"typescript": "^5.8.2",
|
||||
"vitepress": "^1.6.4",
|
||||
"vitest": "^4.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user