content-forge-vault/00-inbox/2026-03-18-opencli-research.md
2026-03-19 02:00:01 +08:00

162 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
id: 2026-03-18-opencli-research
title: OpenCLI 深度研究:把任何网站变成 CLI
slug: opencli-research
status: inbox
content_type: article
language: zh-CN
source_urls:
- https://github.com/jackwener/opencli
tags:
- cli-tool
- browser-automation
- ai-agent
- web-scraping
- open-source
created_at: 2026-03-18T00:00:00+08:00
updated_at: 2026-03-18T00:00:00+08:00
---
# OpenCLI 深度研究:把任何网站变成 CLI
> Make any website your CLI. Zero risk · Reuse Chrome login · AI-powered discovery
## 项目信息
- 仓库: git@github.com:jackwener/opencli.git
- npm: @jackwener/opencli
- 协议: BSD-3-Clause
- Node.js >= 18
## 核心定位
把任何网站变成命令行工具——复用 Chrome 登录态零风险AI 驱动自动发现 API。
## 架构总览
```
┌────────────────────────────────────────────────────────────────────────┐
│ opencli CLI (main.ts) │
│ Commander.js 命令树 │
├──────────┬─────────────┬──────────────┬───────────────────────────────┤
│ 内置命令 │ 动态站点命令 │ AI Agent 命令 │ 管理命令 │
│ list │ bilibili/* │ explore │ validate / verify │
│ doctor │ twitter/* │ synthesize │ setup │
│ setup │ zhihu/* │ generate │ │
│ │ ...18 sites │ cascade │ │
├──────────┴─────────────┴──────────────┴───────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Engine │ │ Registry │ │ Output │ │
│ │ (engine.ts) │────▶│ (registry.ts) │────▶│ (output.ts) │ │
│ │ │ │ │ │ │ │
│ │ • Manifest快速路径│ │ • cli() 注册函数 │ │ • table (默认) │ │
│ │ • FS扫描回退 │ │ • Map<key,Cmd> │ │ • json / yaml │ │
│ │ • YAML 自动解析 │ │ • Strategy enum │ │ • markdown / csv│ │
│ │ • TS 惰性加载 │ │ • Arg 接口 │ │ │ │
│ └────────┬────────┘ └─────────────────┘ └─────────────────┘ │
│ │ │
│ ┌────────▼────────┐ ┌─────────────────┐ │
│ │ Pipeline │ │ Browser │ │
│ │ (pipeline/) │ │ (browser.ts) │ │
│ │ │ │ │ │
│ │ YAML 声明式引擎 │◀───▶│ PlaywrightMCP │ │
│ │ 14 种 Step │ │ JSON-RPC ↔ Chrome│ │
│ │ 模板表达式 │ │ Page 抽象层 │ │
│ └─────────────────┘ └─────────────────┘ │
└────────────────────────────────────────────────────────────────────────┘
```
## 核心设计 1双引擎
YAML 声明式 + TypeScript 编程式双引擎,共享同一个 Registry 和 Browser 抽象层。
数据结构 CliCommand 的 func 和 pipeline 二选一——消除引擎切换的特殊情况处理。
- YAML: src/clis/<site>/<name>.yaml14 种 Pipeline Step放入即自动注册
- TS: src/clis/<site>/<name>.ts通过 cli() 函数注册,首次执行时才惰性加载
- 发现机制: cli-manifest.json 快速路径 + FS scan 回退(生产零开销 + 开发热加载)
Pipeline 步骤:
- 数据获取: navigate, fetch, evaluate, snapshot, intercept, tap
- 数据变换: select, map, filter, sort, limit
- UI 操作: click, type, wait, press
- 模板语法: \${{ item.field }}, \${{ args.limit }}, \${{ index + 1 }}
## 核心设计 25 级认证策略
```
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ PUBLIC │───▶│ COOKIE │───▶│ HEADER │───▶│INTERCEPT │───▶│ UI │
│ Tier 1 │ │ Tier 2 │ │ Tier 3 │ │ Tier 4 │ │ Tier 5 │
│ ~1s ⚡ │ │ ~7s 🔄 │ │ ~7s 🔄 │ │ ~10s 🔄 │ │ ~15s+ 🐌│
├──────────┤ ├──────────┤ ├──────────┤ ├──────────┤ ├──────────┤
│HackerNews│ │ Bilibili │ │ Twitter │ │ 小红书 │ │ 遗留站点 │
│ V2EX/BBC │ │ Zhihu │ │ GraphQL │ │ Pinia+ │ │ │
│ GitHub │ │ Reddit │ │ │ │ XHR Hook │ │ │
└──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘
```
cascade 命令自动逐级探测:对目标 URL 依次尝试 PUBLIC → COOKIE → HEADER第一个成功的就是最佳策略。
## 核心设计 3AI 自动发现
```
explore <url> → 导航 + 自动滚动 + fuzzing + 网络捕获 + 框架检测 + 端点评分 + 能力推理
synthesize <site> → 从 explore 产物生成 YAML 候选
generate <url> → explore + synthesize + register 一键完成
```
端点评分系统: JSON +10, API路径 +3, 搜索参数 +3, 分页 +2, 有数据 +5, 空数据 -3反爬检测。阈值 ≥5 才保留。
## 核心设计 4拦截器系统
三种拦截模式:
- 全局拦截: installInterceptor() — 持久 monkey-patch累积捕获
- 读取+清空: getInterceptedRequests() — 读取后清空
- tap 拦截: 临时拦截 + Promise 等待 + 自动恢复原函数
tap 步骤是最精妙的设计——不自己构造签名,而是调用目标站点的 Pinia/Vuex Store Action让前端框架自己完成鉴权再拦截网络响应取数据。「用敌人的武器打败敌人」。
## 浏览器层
通过 Playwright MCP Bridge Chrome 扩展连接用户已登录的浏览器——不启动新浏览器实例,复用用户的 Cookie/Session/登录态。这是「零风险」的核心保障。
Page 抽象层 (IPage): goto, evaluate, snapshot, click, autoScroll, installInterceptor, getInterceptedRequests
## 支持站点18 个100+ 命令)
Public无需浏览器: hackernews, bbc, github, v2ex(部分)
Browser需 Chrome 登录):
- bilibili (11 cmds): hot, search, me, favorite, history, feed, subtitle, dynamic, ranking, following, user-videos
- twitter (17 cmds!): trending, bookmarks, profile, search, timeline, following, followers, notifications, post, reply, delete, like, article, follow, unfollow, bookmark, unbookmark
- zhihu (3), xiaohongshu (5), xueqiu (6), reddit (4), weibo, boss, coupang, youtube, yahoo-finance, reuters, smzdm, ctrip, v2ex(部分)
## 技术栈
CLI: Commander.js | 浏览器: Playwright MCP Bridge | YAML: js-yaml | 输出: cli-table3 + chalk | 构建: TypeScript | 测试: Vitest (~52 E2E) | 运行时: Node.js >= 18
## 架构亮点
1. CliCommand 的 func/pipeline 二选一——消除引擎切换 if/elseGood Taste
2. Manifest 快速路径 + FS scan 回退——零开销启动 + 无缝开发
3. 5 级策略 + cascade 自动探测——认证复杂度分层管理
4. tap 步骤Store Action Bridge——用框架自己的能力绕过签名
5. Page 抽象层 (IPage)——浏览器操作解耦,方便测试 mock
6. explore 端点评分——把 AI 发现从「试错」降为「打分排序」
## 潜在问题
- Twitter Bearer Token 硬编码(轮换风险)
- evaluate 步骤 JS 注入用字符串拼接XSS 向量,虽运行在用户自己浏览器)
- 无重试机制(网络抖动直接失败)
- E2E 测试依赖真实站点(站点改版易失败)
## 选题角度思考
- 「把任何网站变成 CLI」的产品思路——从 API wrapper 到 AI 自动发现的演进
- 双引擎设计的 Good Taste——YAML 声明式 vs TS 编程式的边界在哪里
- 5 级认证策略——Web 反爬对抗的分层哲学
- tap 步骤的精妙设计——用前端框架自己的能力打败它
- 对 AI Agent 工具生态的启示——explore + synthesize + cascade 三件套