Skip to content

OpenCLI 开源项目解读

项目信息

  • 项目名称:OpenCLI

  • 项目描述:OpenCLI 是一个让你通过命令行操作网站、控制 Electron 应用、统一管理 CLI 工具的 AI 驱动型自动化平台。

  • 项目地址:https://github.com/jackwener/OpenCLI

  • 核心功能

    • 70+ 预置网站适配器(bilibili、twitter、hackernews 等)
    • 浏览器自动化(复用登录会话,无需密码)
    • Electron 应用控制(Cursor、ChatGPT 等)
    • CLI 工具统一管理
    • AI Agent 友好的技能系统

1. 项目概览

1.1 项目定位与核心价值

一句话定位:OpenCLI 是一个将网站、浏览器会话、Electron 应用和本地工具转换为确定性命令行接口的 AI 驱动型自动化平台。

核心痛点解决

  1. 网站操作自动化困难:传统爬虫易被反爬虫拦截,需要复用已登录会话。
  2. AI Agent 缺乏可靠的网站操作能力:需要标准化接口、安全的登录状态复用、确定性输出。
  3. CLI 工具碎片化:各种工具分散,缺乏统一发现和调用机制。
  4. Electron 应用自动化:桌面应用缺乏自动化接口。

目标用户

  • 普通用户:通过命令行快速使用网站功能
  • AI Agent 开发者:为 Agent 提供浏览器操作和 CLI 调用能力
  • 网站自动化开发者:编写适配器将网站转为 CLI 命令
  • Claude Code / Cursor 用户:使用内置技能快速操作网站

1.2 目标用户与使用场景

核心场景

  • AI Agent 实时网站操作:Agent 通过 OpenCLI 操作用户已登录的浏览器
  • 确定性网站 CLI 命令:使用预置适配器(70+ 网站)
  • CLI 工具统一管理:作为统一入口发现、安装、调用各种 CLI
  • Electron 应用控制:直接控制 Cursor、ChatGPT 等桌面应用

1.3 核心技术亮点

  • 分层插件化架构:抽象浏览器操作、插件化适配器
  • 安全的会话复用:Daemon + Extension 架构,多层安全防御
  • AI Agent 友好:结构化技能、确定性输出
  • 70+ 预置网站适配器:开箱即用
  • 多种浏览器连接方式:BrowserBridge(扩展)、CDPBridge(直接 CDP)
  • 策略模式适配器:PUBLIC/COOKIE/HEADER/INTERCEPT/UI 多种策略

1.4 技术栈与选型对比

层级技术选型
运行时Node.js >= 21.0.0
CLI 框架Commander.js
浏览器通信Chrome DevTools Protocol (CDP), WebSocket (ws)
数据格式JSON, YAML, CSV, Markdown
测试框架Vitest
文档工具VitePress

关键选型决策

  • 直接使用 CDP 而非 Puppeteer:可连接任意 Chrome 实例、复用登录会话
  • Daemon + Extension 架构:安全地桥接 CLI 和浏览器
  • Skills 系统:为 AI Agent 提供结构化工作流

2. 整体架构设计

2.1 架构概述

OpenCLI 采用分层插件化架构,通过标准化的接口将 CLI、浏览器自动化、网站适配器和 AI 技能组合在一起。架构设计的核心理念是:

  • 抽象浏览器操作:通过 IPage 接口统一不同浏览器控制方式
  • 插件化适配器:网站适配器可以独立开发和注册
  • 安全的会话复用:通过 Daemon + Extension 架构复用浏览器登录状态
  • AI Agent 友好:提供结构化的技能和确定性的输出

2.2 整体架构图 (ASCII)

text
┌─────────────────────────────────────────────────────────────────────────────┐
│                         用户 / AI Agent 层                                   │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐                   │
│  │   人类用户   │    │  Claude Code │    │   其他 Agent │                   │
│  └──────┬───────┘    └──────┬───────┘    └──────┬───────┘                   │
└─────────┼───────────────────┼───────────────────┼───────────────────────────┘
          │                   │                   │
          └───────────────────┴───────────────────┘

┌─────────────────────────────▼───────────────────────────────────────────────┐
│                         CLI 层 (main.ts + cli.ts)                            │
│  ┌───────────────────────────────────────────────────────────────────────┐ │
│  │  Commander.js 命令解析器                                               │ │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐                 │ │
│  │  │  内置命令    │  │  适配器命令   │  │ 外部 CLI     │                 │ │
│  │  │  (list,     │  │  (bilibili,   │  │  (gh,        │                 │ │
│  │  │   doctor)   │  │   twitter)    │  │   docker)    │                 │ │
│  │  └──────────────┘  └──────────────┘  └──────────────┘                 │ │
│  └───────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────┬───────────────────────────────────────────────┘

              ┌───────────────┴───────────────┐
              │                               │
┌─────────────▼─────────────┐    ┌────────────▼─────────────┐
│    适配器层 (registry.ts) │    │  管道执行层 (pipeline/)  │
│  ┌───────────────────────┐│    ┌─────────────────────────┐│
│  │ 策略枚举:            ││    │ 步骤类型:               ││
│  │  PUBLIC/COOKIE/      ││    │  fetch/extract/         ││
│  │  HEADER/INTERCEPT/UI ││    │  download/transform     ││
│  └───────────────────────┘│    └─────────────────────────┘│
│  ┌───────────────────────┐│    ┌─────────────────────────┐│
│  │ 70+ 网站适配器       ││    │ 执行引擎 (executor.ts) ││
│  └───────────────────────┘│    └─────────────────────────┘│
└─────────────┬─────────────┘    └────────────┬──────────────┘
              │                               │
              └───────────────┬───────────────┘

┌─────────────────────────────▼───────────────────────────────────────────────┐
│                      浏览器控制层 (src/browser/)                            │
│  ┌───────────────────────────────────────────────────────────────────────┐ │
│  │  IPage 接口抽象 (types.ts)                                             │ │
│  ├───────────────────────────────────────────────────────────────────────┤ │
│  │  ┌──────────────────┐    ┌──────────────────┐                         │ │
│  │  │ BrowserBridge    │    │   CDPBridge      │                         │ │
│  │  │ (Extension模式)  │    │  (直接CDP连接)   │                         │ │
│  │  └────────┬─────────┘    └────────┬─────────┘                         │ │
│  └───────────┼─────────────────────────┼───────────────────────────────────┘ │
└──────────────┼─────────────────────────┼───────────────────────────────────────┘
               │                         │
    ┌──────────▼──────────┐    ┌─────────▼─────────┐
    │ DOM 快照与提取      │    │ 网络请求拦截     │
    │ (dom-snapshot.ts)  │    │ (network-cache.ts)│
    └─────────────────────┘    └───────────────────┘
               │                         │
┌──────────────▼─────────────────────────▼───────────────────────────────────┐
│                        通信层 (Daemon + Extension)                         │
│  ┌─────────────────────────┐            ┌─────────────────────────┐       │
│  │  daemon.ts              │            │  Browser Extension      │       │
│  │  (本地 HTTP 服务)       │◄──────────►│  (WebSocket 连接)       │       │
│  └─────────────────────────┘            └─────────────────────────┘       │
└─────────────────────────────────────────────────────────────────────────────┘


                    ┌───────────────────┐
                    │ Chrome/Chromium   │
                    │ (已登录会话)      │
                    └───────────────────┘

2.3 分层职责说明

职责核心文件
CLI 层命令解析、参数处理、输出格式化main.ts, cli.ts, output.ts
适配器层70+ 网站适配器、命令注册、策略管理registry.ts, discovery.ts, clis/
浏览器控制层IPage 抽象、BrowserBridge/CDPBridge、DOM 操作browser/page.ts, bridge.ts, cdp.ts
通信层Daemon HTTP+WS 服务、扩展通信daemon.ts, extension/src/

2.4 完整目录树

shell
opencli/
├── src/                                   # 【核心基建】源代码主目录
   ├── main.ts                            # 【核心基建】CLI 入口,快速路径优化
   ├── cli.ts                             # 【核心基建】CLI 命令注册与 Commander 集成
   ├── daemon.ts                          # 【核心基建】本地守护进程,HTTP+WS 服务
   ├── types.ts                           # 【核心基建】核心类型定义(IPage, etc.)
   ├── registry.ts                        # 【核心基建】命令注册中心(globalThis 单例)
   ├── discovery.ts                       # 【核心基建】适配器/插件发现与加载
   ├── execution.ts                       # 【核心基建】命令执行引擎
   ├── launcher.ts                        # 【核心基建】浏览器会话启动器
   ├── output.ts                          # 【核心基建】输出格式化(table/json/yaml/md/csv)
   ├── errors.ts                          # 【核心基建】错误定义与处理
   ├── constants.ts                       # 【核心基建】常量定义
   ├── utils.ts                           # 【工具集】通用工具函数
   ├── logger.ts                          # 【工具集】日志工具
   ├── version.ts                         # 【工具集】版本信息
   ├── hooks.ts                           # 【工具集】生命周期钩子
   ├── update-check.ts                    # 【工具集】更新检查
   ├── external.ts                        # 【业务模块】外部 CLI 集成
   ├── plugin.ts                          # 【业务模块】插件系统
   ├── plugin-scaffold.ts                 # 【业务模块】插件脚手架生成
   ├── plugin-manifest.ts                 # 【工具集】插件 manifest 处理
   ├── commanderAdapter.ts                # 【工具集】Commander.js 适配器注册
   ├── completion.ts                      # 【工具集】Shell 补全生成
   ├── completion-fast.ts                 # 【工具集】快速补全(从 manifest 读取)
   ├── completion-shared.ts               # 【工具集】补全共享逻辑
   ├── validate.ts                        # 【工具集】适配器验证
   ├── verify.ts                          # 【工具集】适配器验证+测试
   ├── build-manifest.ts                  # 【工具集】构建命令 manifest
   ├── capabilityRouting.ts               # 【工具集】功能路由
   ├── node-network.ts                    # 【工具集】Node.js 网络工具
   ├── runtime.ts                         # 【工具集】运行时检测
   ├── runtime-detect.ts                  # 【工具集】运行时环境检测
   ├── diagnostic.ts                      # 【工具集】诊断工具
   ├── doctor.ts                          # 【工具集】Doctor 命令实现
   ├── electron-apps.ts                   # 【业务模块】Electron 应用控制
   ├── interceptor.ts                     # 【工具集】网络拦截器
   ├── snapshotFormatter.ts               # 【工具集】DOM 快照格式化
   ├── tui.ts                             # 【UI 视图】终端 UI 组件
   ├── analysis.ts                        # 【工具集】网站分析(反爬虫检测等)
   ├── package-paths.ts                   # 【工具集】包路径解析
   ├── external-clis.yaml                 # 【配置】外部 CLI 定义

   ├── browser/                           # 【核心基建】浏览器控制模块
   ├── index.ts                       # 【核心基建】模块导出入口
   ├── bridge.ts                      # 【核心基建】BrowserBridge - 扩展通信
   ├── cdp.ts                         # 【核心基建】CDPBridge - 直接 CDP 连接
   ├── page.ts                        # 【核心基建】Page - IPage 实现
   ├── base-page.ts                   # 【核心基建】BasePage - 基础实现
   ├── dom-snapshot.ts                # 【核心基建】DOM 快照生成
   ├── dom-helpers.ts                 # 【工具集】DOM 帮助函数
   ├── html-tree.ts                   # 【工具集】HTML 树生成
   ├── extract.ts                     # 【工具集】内容提取(文章/Markdown)
   ├── find.ts                        # 【工具集】元素查找
   ├── target-resolver.ts             # 【核心基建】目标解析(CSS+数字引用)
   ├── target-errors.ts               # 【工具集】目标相关错误
   ├── shape.ts                       # 【工具集】数据形状推断
   ├── shape-filter.ts                # 【工具集】形状过滤
   ├── network-key.ts                 # 【工具集】网络请求 Key 生成
   ├── network-cache.ts               # 【核心基建】网络缓存(保存请求供分析)
   ├── analyze.ts                     # 【核心基建】网站分析(反爬虫检测)
   ├── stealth.ts                     # 【核心基建】反检测脚本注入
   ├── daemon-client.ts               # 【工具集】Daemon 客户端
   ├── verify-fixture.ts              # 【工具集】验证夹具
   ├── errors.ts                      # 【工具集】错误定义
   ├── compound.ts                    # 【工具集】复合操作
   ├── tabs.ts                        # 【工具集】标签页管理
   ├── utils.ts                       # 【工具集】浏览器工具函数
   ├── article-extract.ts             # 【工具集】文章提取(Readability)
   └── __fixtures__/                  # 【配置】测试夹具

   ├── pipeline/                          # 【核心基建】管道执行引擎
   ├── index.ts                       # 【核心基建】模块导出
   ├── executor.ts                    # 【核心基建】管道执行器
   ├── registry.ts                    # 【核心基建】管道步骤注册
   └── steps/                         # 【核心基建】内置管道步骤
       ├── browser.ts                 # 浏览器操作步骤
       ├── fetch.ts                   # 网络请求步骤
       └── download.test.ts           # 下载步骤测试

   ├── download/                          # 【业务模块】下载功能
   ├── index.ts                       # 【核心基建】下载模块入口
   ├── media-download.ts              # 【业务模块】媒体下载
   ├── article-download.ts            # 【业务模块】文章下载
   └── progress.ts                    # 【工具集】下载进度显示

   └── commands/                          # 【业务模块】内置命令实现
       └── daemon.ts                      # daemon 子命令

├── clis/                                  # 【业务模块】网站适配器目录(70+ 网站)
   ├── _shared/                          # 【工具集】适配器共享代码
   ├── _shared/desktop-commands.js       # 【工具集】桌面应用命令
   ├── bilibili/                         # 【业务模块】Bilibili 适配器
   ├── hot.js                        # 热门
   ├── search.js                     # 搜索
   ├── video.js                      # 视频
   ├── download.js                   # 下载
   └── ...
   ├── twitter/                          # 【业务模块】Twitter/X 适配器
   ├── hackernews/                       # 【业务模块】HackerNews 适配器
   ├── reddit/                           # 【业务模块】Reddit 适配器
   ├── 1688/                             # 【业务模块】1688 适配器
   └── ... (70+ 网站适配器)

├── extension/                            # 【核心基建】浏览器扩展(Browser Bridge)
   ├── manifest.json                     # 【配置】扩展 manifest
   ├── src/background.ts                 # 【核心基建】Background script
   ├── src/cdp.ts                        # 【核心基建】CDP 封装
   ├── src/identity.ts                   # 【工具集】身份验证
   ├── src/protocol.ts                   # 【工具集】协议定义
   ├── popup.html                        # 【UI 视图】Popup 页面
   ├── popup.js                          # 【UI 视图】Popup 脚本
   └── package.json                      # 【配置】扩展依赖

├── skills/                               # 【工具集】AI Agent 技能
   ├── opencli-adapter-author/           # 【工具集】适配器编写技能
   ├── SKILL.md                      # 技能主文件
   └── references/                   # 参考文档
   ├── opencli-autofix/                  # 【工具集】自动修复技能
   ├── opencli-browser/                  # 【工具集】浏览器操作参考
   ├── opencli-usage/                    # 【工具集】使用指南
   └── smart-search/                     # 【工具集】智能搜索

├── docs/                                 # 【配置】项目文档
   ├── adapters/                         # 适配器文档
   └── guide/                            # 使用指南

├── scripts/                              # 【工具集】构建和部署脚本
   ├── clean-dist.cjs                    # 清理 dist
   ├── copy-yaml.cjs                     # 复制 yaml 文件
   ├── fetch-adapters.js                 # 获取适配器
   └── postinstall.js                    # 安装后脚本

├── autoresearch/                         #  自动化研究相关

├── tests/                                # 【质量保证】测试目录

├── .github/                              # 【配置】GitHub Actions CI/CD

├── package.json                          # 【配置】项目配置
├── tsconfig.json                         # 【配置】TypeScript 配置
├── cli-manifest.json                     # 【配置】命令 manifest(构建生成)
├── README.md                             # 【配置】英文 README
├── README.zh-CN.md                       # 【配置】中文 README
├── LICENSE                               # 【配置】许可证
└── PRIVACY.md                            # 【配置】隐私政策

3. 模块依赖与调用关系

3.1 全局入口与核心路由

逻辑说明

OpenCLI 的入口流程设计为快速路径优先,避免为简单命令付出完整启动成本:

  1. 快速路径 (--version, completion, --get-completions):

    • 直接处理,不进行适配器发现
    • 读取缓存的 manifest 文件获取补全信息
  2. 完整路径(其他命令):

    • 并行执行:用户适配器兼容性检查 + 内置适配器发现
    • 加载用户适配器(~/.opencli/clis/
    • 发现插件
    • 注册更新检查钩子
    • 解析命令并执行

调用拓扑 (plainText)

text
main.ts (入口)

  ├─── 快速路径检查
  │     ├───> --version → 直接输出版本号 → 退出
  │     ├───> completion <shell> → 打印补全脚本 → 退出
  │     └───> --get-completions → 读取 manifest → 输出补全 → 退出

  └─── 完整路径 (普通命令)

        ├─── 并行启动
        │     ├───> ensureUserCliCompatShims()
        │     ├───> ensureUserAdapters()
        │     └───> discoverClis(BUILTIN_CLIS)

        ├───> discoverClis(USER_CLIS)
        ├───> discoverPlugins()

        ├───> registerUpdateNoticeOnExit()
        ├───> checkForUpdateBackground()

        └───> cli.ts → runCli()

              └───> Commander.js 解析命令

                    ├───> 内置命令处理
                    │     ├─── list
                    │     ├─── doctor
                    │     ├─── browser <subcmd>
                    │     ├─── plugin <subcmd>
                    │     └─── ...

                    ├───> 适配器命令处理
                    │     └───> execution.ts → executeCommand()
                    │           │
                    │           ├───> (如有必要) launcher.ts → 启动浏览器会话
                    │           ├───> 执行适配器 func() 或 pipeline
                    │           └───> output.ts → 格式化输出

                    └───> 外部 CLI 处理
                          └───> external.ts → 透传到外部工具

3.2 核心业务实体与关联

实体定义

实体定义核心属性
CliCommand一个 CLI 命令(网站适配器或内置命令)site, name, strategy, args, func/pipeline
IPage浏览器页面的抽象接口goto, evaluate, click, typeText, snapshot, 等
Strategy适配器认证/执行策略枚举PUBLIC, COOKIE, HEADER, INTERCEPT, UI
Registry全局命令注册中心Map<site/name, CliCommand>

实体引用拓扑 (ASCII)

text
[CliCommand] (策略: Strategy)

  ├─── 1:1 ──> [IPage] (浏览器页面抽象)
  │            │
  │            ├───> BrowserBridge 实现
  │            └───> CDPBridge 实现

  ├─── 1:N ──> [Arg] (命令参数定义)

  └─── 注册到

        [Registry] (全局单例,使用 globalThis)

4. 核心模块详解

4.1 浏览器控制模块 (src/browser/)

模块名:浏览器控制模块

设计说明:采用桥接模式 + 策略模式设计:

  • IPage 接口:定义统一页面操作抽象
  • BrowserBridge:通过浏览器扩展 + Daemon 通信
  • CDPBridge:直接连接 Chrome DevTools Protocol(用于 Electron)
  • Page 类:统一实现,依赖底层桥接

关键技术点

  1. 目标解析 (Target Resolver)

    • 支持 CSS 选择器和数字引用(来自 snapshot)
    • 提供稳定的元素重识别机制(应对 DOM 变化)
    • 匹配级别:exact → stable → reidentified
  2. Stealth 脚本

    • 注入各种反检测脚本
    • 隐藏自动化特征
  3. 网络缓存

    • 保存网络请求用于后续分析
    • 支持按 key 检索完整响应

内部结构图 (ASCII)

text
┌─────────────────────────────────────────────────────────────────────────┐
│                          IPage 接口 (types.ts)                            │
│  ┌─────────────────────────────────────────────────────────────────────┐│
│  │  goto(url)         evaluate(js)        click(ref)                   ││
│  │  typeText(ref, text)  pressKey(key)    snapshot(opts)               ││
│  │  wait(opts)          tabs()             networkRequests()           ││
│  └─────────────────────────────────────────────────────────────────────┘│
└─────────────────────────────┬─────────────────────────────────────────────┘

          ┌───────────────────┴───────────────────┐
          │                                       │
┌─────────▼──────────┐                   ┌────────▼─────────┐
│  BrowserBridge     │                   │   CDPBridge      │
│  (Extension +     │                    │  (直接 CDP)      │
│   Daemon)         │                    │                  │
│  ┌─────────────┐ │                     │ ┌─────────────┐ │
│  │ bridge.ts   │ │                     │ │ cdp.ts      │ │
│  │ 连接扩展    │ │                      │ │ 连接 Chrome │ │
│  └─────────────┘ │                     │ └─────────────┘ │
└─────────┬─────────┘                    └────────┬─────────┘
          │                                       │
          └───────────────┬───────────────────────┘

                  ┌───────▼───────┐
                  │   Page 类     │
                  │  (page.ts)   │
                  └───────┬───────┘

         ┌────────────────┼────────────────┐
         │                │                │
    ┌────▼────┐    ┌────▼────┐    ┌──────▼──────┐
    │ DOM快照  │    │ 元素查找 │    │ 网络拦截   │
    │ (dom-   │    │ (find.ts)│    │ (network-  │
    │ snapshot│    │          │    │  cache.ts) │
    │ .ts)    │    └─────────┘    └────────────┘
    └─────────┘

    ┌────▼────┐
    │ 目标解析 │
    │ (target-│
    │ resolver│
    │ .ts)    │
    └─────────┘

4.2 适配器注册与发现 (src/registry.ts + discovery.ts)

模块名:适配器注册与发现模块

设计说明:采用注册中心模式 + 懒加载设计:

  • 使用 globalThis 确保单例(应对 npm link)
  • 支持多种来源:内置、用户目录、插件
  • 策略自动归一化(strategy → browser + navigateBefore)

策略归一化规则

StrategybrowsernavigateBefore说明
PUBLICfalseundefined不需要浏览器
COOKIEtrue"https://domain"需要浏览器,预导航
HEADERtrue"https://domain"需要自定义 header
INTERCEPTtruetrue需要拦截网络
UItruetrue需要 UI 自动化

内部结构图

text
┌─────────────────────────────────────────────────────────────────────────┐
│                        Registry (registry.ts)                           │
│  ┌─────────────────────────────────────────────────────────────────────┐│
│  │  globalThis.__opencli_registry__: Map<string, CliCommand>           ││
│  └─────────────────────────────────────────────────────────────────────┘│
│  ┌─────────────────────────────────────────────────────────────────────┐│
│  │  cli(opts) → 注册命令                                               ││
│  │  registerCommand(cmd) → 归一化后注册                                ││
│  │  getRegistry() → 获取全局 Map                                       ││
│  │  fullName(cmd) → "site/name"                                        ││
│  └─────────────────────────────────────────────────────────────────────┘│
└─────────────────────────────┬─────────────────────────────────────────────┘

┌─────────────────────────────▼─────────────────────────────────────────────┐
│                        Discovery (discovery.ts)                          │
│  ┌─────────────────────────────────────────────────────────────────────┐│
│  │  discoverClis(dir) → 扫描目录下的适配器                              ││
│  │  - 支持 .js/.ts/.yaml 格式                                           ││
│  │  - 递归扫描子目录                                                    ││
│  ├─────────────────────────────────────────────────────────────────────┤│
│  │  discoverPlugins() → 扫描已安装插件                                  ││
│  │  ensureUserAdapters() → 确保用户适配器目录存在                        ││
│  └─────────────────────────────────────────────────────────────────────┘│
└───────────────────────────────────────────────────────────────────────────┘

         ┌────────────────────┼────────────────────┐
         │                    │                    │
    ┌────▼────┐        ┌─────▼─────┐       ┌──────▼──────┐
    │ 内置    │        │ 用户目录  │       │ 插件        │
    │ clis/   │        │ ~/.opencli│       │ 动态加载    │
    │         │        │ /clis/    │       │             │
    └─────────┘        └───────────┘       └─────────────┘

4.3 守护进程 (src/daemon.ts)

设计说明

守护进程是 OpenCLI 安全架构的核心,采用多层防御设计:

  • Origin 检查:只接受 chrome-extension:// 请求
  • 自定义 Header:要求 X-OpenCLI(浏览器无法跨域发送)
  • 无 CORS:防止网页直接调用
  • Body 大小限制:防止 OOM 攻击

内部结构图

text
┌─────────────────────────────────────────────────────────────────────────┐
│                        Daemon (daemon.ts)                               │
│  ┌─────────────────────────────────────────────────────────────────────┐│
│  │  HTTP Server (Node.js http.createServer)                            ││
│  │  监听: 127.0.0.1:19825 (默认)                                       ││
│  └─────────────────────────────────────────────────────────────────────┘│
│  ┌─────────────────────────────────────────────────────────────────────┐│
│  │  HTTP 端点                                                          ││
│  │  GET  /ping    ──┐                                                  ││
│  │  GET  /status    │  无 X-OpenCLI 要求 (健康检查)                   ││
│  │  GET  /logs      │                                                  ││
│  │  DELETE /logs   ──┘                                                  ││
│  │  POST /command  ──┐                                                 ││
│  │  POST /shutdown   │  要求 X-OpenCLI header                          ││
│  │  OPTIONS *       ──┘  (preflight 返回 204, 无 CORS)                ││
│  └─────────────────────────────────────────────────────────────────────┘│
│  ┌─────────────────────────────────────────────────────────────────────┐│
│  │  WebSocket Server (ws library)                                      ││
│  │  路径: /ext                                                         ││
│  │  verifyClient: 检查 Origin 必须是 chrome-extension://               ││
│  └─────────────────────────────────────────────────────────────────────┘│
│  ┌─────────────────────────────────────────────────────────────────────┐│
│  │  内部状态                                                           ││
│  │  extensionWs: WebSocket | null (扩展连接)                           ││
│  │  pending: Map<id, {resolve, reject, timer}> (等待中的命令)          ││
│  │  logBuffer: LogEntry[] (日志环形缓冲区)                             ││
│  └─────────────────────────────────────────────────────────────────────┘│
└───────────────────────────────────────────────────────────────────────────┘


              ┌───────────────────────────────┐
              │  命令流转:                    │
              │  CLI → HTTP → Daemon → WS →  │
              │  Extension → 执行 → WS →     │
              │  Daemon → HTTP → CLI         │
              └───────────────────────────────┘

关键端点

  • GET /ping:健康检查(无 X-OpenCLI 要求)
  • GET /status:Daemon 状态
  • POST /command:执行浏览器命令
  • POST /shutdown:关闭 Daemon

心跳与重连机制

  • Extension 每 15s 发送 ping
  • 错过 2 个 pong 则认为连接丢失
  • 关闭连接,清理 pending 命令

5. 关键数据流程

5.1 浏览器命令执行流程

场景说明:用户执行 opencli browser open https://example.com

流转时序图 (Mermaid)

5.2 网站适配器执行流程

场景说明:用户执行 opencli bilibili hot --limit 5,这是典型的适配器使用流程。

流转时序图 (Mermaid)

6. 接口与契约规范

6.1 核心内部模块契约 (TypeScript)

IPage - 浏览器页面抽象

IPage - 浏览器页面抽象

typescript
/**
 * Page interface: type-safe abstraction over browser page.
 * All pipeline steps and CLI adapters should use this interface.
 */
export interface IPage {
  goto(url: string, options?: { waitUntil?: 'load' | 'none'; settleMs?: number }): Promise<void>;
  evaluate(js: string): Promise<any>;
  evaluateWithArgs?(js: string, args: Record<string, unknown>): Promise<any>;
  getCookies(opts?: { domain?: string; url?: string }): Promise<BrowserCookie[]>;
  snapshot(opts?: SnapshotOptions): Promise<any>;
  click(ref: string, opts?: { nth?: number; firstOnMulti?: boolean }): Promise<{
    matches_n: number;
    match_level: 'exact' | 'stable' | 'reidentified';
  }>;
  typeText(ref: string, text: string, opts?: { nth?: number; firstOnMulti?: boolean }): Promise<{
    matches_n: number;
    match_level: 'exact' | 'stable' | 'reidentified';
  }>;
  pressKey(key: string): Promise<void>;
  scrollTo(ref: string, opts?: { nth?: number; firstOnMulti?: boolean }): Promise<any>;
  getFormState(): Promise<any>;
  wait(options: number | WaitOptions): Promise<void>;
  tabs(): Promise<any>;
  closeTab?(target?: number | string): Promise<void>;
  newTab?(url?: string): Promise<string | undefined>;
  selectTab(target: number | string): Promise<void>;
  networkRequests(includeStatic?: boolean): Promise<any>;
  consoleMessages(level?: string): Promise<any>;
  scroll(direction?: string, amount?: number): Promise<void>;
  autoScroll(options?: { times?: number; delayMs?: number }): Promise<void>;
  installInterceptor(pattern: string): Promise<void>;
  getInterceptedRequests(): Promise<any[]>;
  waitForCapture(timeout?: number): Promise<void>;
  screenshot(options?: ScreenshotOptions): Promise<string>;
  startNetworkCapture?(pattern?: string): Promise<boolean>;
  readNetworkCapture?(): Promise<unknown[]>;
  setFileInput?(files: string[], selector?: string): Promise<void>;
  insertText?(text: string): Promise<void>;
  closeWindow?(): Promise<void>;
  getCurrentUrl?(): Promise<string | null>;
  getActivePage?(): string | undefined;
  setActivePage?(page?: string): void;
  cdp?(method: string, params?: Record<string, unknown>): Promise<unknown>;
  frames?(): Promise<Array<{ index: number; frameId: string; url: string; name: string }>>;
  evaluateInFrame?(js: string, frameIndex: number): Promise<unknown>;
  nativeClick?(x: number, y: number): Promise<void>;
  nativeType?(text: string): Promise<void>;
  nativeKeyPress?(key: string, modifiers?: string[]): Promise<void>;
}

CliCommand - 命令定义

typescript
/**
 * Core command definition: describes a CLI adapter or built-in command.
 */
export enum Strategy {
  PUBLIC = 'public',
  LOCAL = 'local',
  COOKIE = 'cookie',
  HEADER = 'header',
  INTERCEPT = 'intercept',
  UI = 'ui',
}

export interface Arg {
  name: string;
  type?: string;
  default?: unknown;
  required?: boolean;
  valueRequired?: boolean;
  positional?: boolean;
  help?: string;
  choices?: string[];
}

export interface CliCommand {
  site: string;
  name: string;
  aliases?: string[];
  description: string;
  domain?: string;
  strategy?: Strategy;
  browser?: boolean;
  args: Arg[];
  columns?: string[];
  func?: (page: IPage, kwargs: CommandArgs, debug?: boolean) => Promise<unknown>;
  pipeline?: Record<string, unknown>[];
  timeoutSeconds?: number;
  source?: string;  // 'yaml', 'ts', or plugin name
  footerExtra?: (kwargs: CommandArgs) => string | undefined;
  requiredEnv?: RequiredEnv[];
  validateArgs?: (kwargs: CommandArgs) => void;
  deprecated?: boolean | string;
  replacedBy?: string;
  navigateBefore?: boolean | string;
  defaultFormat?: 'table' | 'plain' | 'json' | 'yaml' | 'csv';
}

6.2 Daemon HTTP API (OpenSpec 格式)

关键端点

  • POST /command:执行浏览器命令(需要 X-OpenCLI header)
  • GET /status:获取 Daemon 状态
  • GET /ping:健康检查
yaml
openapi: 3.0.0
info:
  title: OpenCLI Daemon API
  version: 1.0.0
servers:
  - url: http://127.0.0.1:19825
paths:
  /ping:
    get:
      summary: 健康检查(无 X-OpenCLI 要求)
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
  /status:
    get:
      summary: Daemon 状态
      parameters:
        - name: X-OpenCLI
          in: header
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  pid:
                    type: integer
                  uptime:
                    type: number
                  daemonVersion:
                    type: string
                  extensionConnected:
                    type: boolean
                  extensionVersion:
                    type: string
                  pending:
                    type: integer
                  memoryMB:
                    type: number
                  port:
                    type: integer
  /logs:
    get:
      summary: 获取日志
      parameters:
        - name: X-OpenCLI
          in: header
          required: true
          schema:
            type: string
        - name: level
          in: query
          schema:
            type: string
      responses:
        '200':
          description: OK
    delete:
      summary: 清空日志
      parameters:
        - name: X-OpenCLI
          in: header
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
  /command:
    post:
      summary: 执行浏览器命令
      parameters:
        - name: X-OpenCLI
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [id]
              properties:
                id:
                  type: string
                cmd:
                  type: string
                url:
                  type: string
                timeout:
                  type: number
      responses:
        '200':
          description: OK
        '400':
          description: Bad Request
        '403':
          description: Forbidden
        '408':
          description: Request Timeout
        '503':
          description: Extension Not Connected
  /shutdown:
    post:
      summary: 关闭 daemon
      parameters:
        - name: X-OpenCLI
          in: header
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK

7. 快速开始

7.1 环境配置

  • Node.js >= 21.0.0
  • Chrome/Chromium 浏览器
  • OpenCLI Browser Bridge 扩展

7.2 安装与运行

bash
npm install -g @jackwener/opencli
opencli doctor  # 检查安装
opencli list    # 查看所有命令

7.3 典型用例

bash
# 浏览网站
opencli browser open https://example.com

# 使用预置适配器
opencli bilibili hot --limit 5
opencli hackernews top
opencli reddit hot

# 管理外部 CLI
opencli register mycli
opencli gh pr list