opencli
你是用 OpenCLI 干活的 agent。这个 skill 把 7 个官方子技能合并成一处:先在这里定位任务类型,再去对应章节或 reference 读细节。不要一次性把所有 reference 都读进上下文。
OpenCLI 把任意网站、Electron 桌面应用、或外部 CLI 变成统一的 opencli <site> <command> 操作面,agent 无需屏幕抓取即可驱动。
任务路由 - 先定方向
按任务类型选入口:
| 任务 | 直接读 | 完整手册 |
|---|---|---|
| 读已登录站点数据 / 找对命令 / "opencli 能干嘛" | 下方「§快速上手」 | - |
| 驱动真实浏览器(点击/填表/抓取,无适配器或临时) | 下方「§浏览器原语核心」 | references/browser.md |
| 适配器命令失败了要修 | 下方「§适配器失效自动修复」 | references/autofix.md |
| 给新站点写适配器 / 给现有站点加命令 | references/adapter-author.md |
references/adapter/ |
| 用 sitemap 驱动多步站点流程 | references/browser-sitemap.md |
- |
| 创建/维护站点 sitemap | references/sitemap-author.md |
references/sitemap/sitemap-schema.md |
| 把搜索/查询路由到最佳数据源 | 下方「§智能搜索路由」 | references/search/ |
§快速上手
三大支柱
- 适配器命令 -
opencli <site> <command> [...]。内置适配器在clis/,用户私有适配器在~/.opencli/clis/。每个命令有 strategy 标签(public | cookie | intercept | ui | local,opencli list -f json输出小写),告诉你是否需要 Chrome。 - 浏览器驱动 -
opencli browser *(open/state/click/type/select/find/extract/network…),适配器没覆盖时临时用。 - 当前标签绑定 -
opencli browser <session> bind把用户已经打开并登录的标签绑到会话,后续用opencli browser <session> ...操作。详见references/browser.md。 - 外部 CLI 透传 -
opencli gh、opencli docker等,用opencli external install <name>管理。
安装与体检
# npm 全局安装(推荐,需 Node >= 21)
npm install -g @jackwener/opencli
# 从源码跑(无全局安装)
git clone git@github.com:jackwener/OpenCLI.git
cd OpenCLI && npm install
npx tsx src/main.ts <command> # 同 npm 版操作面
opencli doctor # 浏览器相关任务前必跑
opencli doctor 诊断浏览器桥(daemon + 扩展 + Chrome 接线),范围窄:public/local 适配器、opencli list、插件、外部 CLI 透传不需要它绿;只有 cookie/intercept/ui 适配器和 opencli browser * 需要。失败常见原因:Chrome 没开、扩展没装、调试端口被 1Password 等扩展占用。
Shell completion
opencli completion bash # 也支持 zsh / fish,输出到 stdout,按 shell 惯例 source 或保存
其他顶层命令
opencli daemon status|stop|restart # 管理 opencli 后台 daemon
opencli auth status|refresh # 看登录态 / 刷新已登录站点会话保活
opencli skills list|read # 列出 / 读取捆绑的 opencli-* 技能
opencli convention-audit [target] # 扫描适配器是否符合 agent-native 约定(开发者用)
全局 flag
| flag | 作用 |
|---|---|
--profile <name> |
所有命令可加,路由到指定 Chrome profile 别名(等价于 OPENCLI_PROFILE) |
按 strategy 看命令需要什么
opencli list 上的 strategy 标签 |
需要什么 |
|---|---|
public |
无 - 纯 HTTP,不碰浏览器 |
cookie |
Chrome 登录目标站点 + 装扩展,命令从 live session 取凭证,不用重登 |
intercept |
同 cookie,加开一个自动化窗口抓签名请求 |
ui |
同 cookie,完整 DOM 交互 |
local |
无浏览器,连本地/dev 端点 |
术语对照:references/ 里的文档用上游文档层术语(大写 6 元组),运行时 opencli list -f json 实际输出小写 tag,二者对应关系如下:
| references 里的术语 | 运行时 list -f json 的 strategy 值 |
|---|---|
| PUBLIC_API | public |
| COOKIE_API | cookie |
| INTERCEPT | intercept |
| UI_SELECTOR | ui |
| LOCAL | local |
| PAGE_FETCH / DOM_STATE | (文档层概念,运行时无对应 tag) |
Electron 桌面应用(cursor/codex/chatwise/discord-app/doubao-app/antigravity/chatgpt-app)走 CDP 连运行中的应用,同 cookie-less 流程,调用前确保应用在跑。
⚠️ 适配器返回 [] / 空时怎么排查
带 domain 的 cookie 适配器(如 zhihu hot)会自己先导航到 https://<domain> 再取数,不依赖前台标签。返回空时按序排查:
- 先重跑一次 - 首次连接/冷启动偶发空结果,重跑即恢复(实测:前台
about:blank时zhihu hot也正常)。 - 查登录态 - 用
opencli browser <session> open https://<site>/打开站点,看是否跳登录页;跳了就在 Chrome 里登录。 - 换查询/入口重试 - 平台反爬降级、软 404 会返回结构正常但空的 payload(见「§适配器失效自动修复」的"空 ≠ 坏了")。
- 以上都排除仍复现,才进
--trace retain-on-failure修复流程。
真正依赖当前页面状态的是无 domain 的 ui 适配器(如 antigravity 等桌面 App 操作,navigateBefore=true,不预导航直接操作当前页面)——用它们时确保目标 App/页面已在运行。
public/local 适配器不碰浏览器(browser: false,Node 侧纯 fetch 或连本地端点),不带浏览器 cookie,与前台标签无关。
发现命令 - 别读文档,跑命令
opencli list # 表格,按站点分组
opencli list -f json # 机器可读;喂给 jq 或 agent
opencli list | grep -i twitter # 找某站点的命令
opencli <site> --help # 看该站点的子命令 + flag
opencli <site> <command> --help # 看位置参数和命令专属 flag
别硬编码适配器列表 - 100+ 站点每周都在变。opencli list -f json 是真相源,每条命令一个 entry,含 {site, name, aliases, description, strategy, browser, args, columns, ...}。
高变更的已登录站点,先查适配器有没有现成工作流再裸开浏览器(如 ChatGPT web 有会话读取、Deep Research 结果抽取等高层命令,用 opencli chatgpt --help 或 opencli list -f json 发现当前面)。
通用 flag(每个适配器命令都生效)
| flag | 作用 |
|---|---|
-f, --format <fmt> |
table(TTY 默认)· yaml(非 TTY 默认)· json · plain · md · csv。agent 几乎总用 -f json;plain 取单个主字段(response/content 等),适合管道。个别命令经 cmd.defaultFormat 覆盖默认(如 chat 类默认 plain),别想当然,看 --help。 |
-v, --verbose |
调试日志 + 失败堆栈 |
命令专属 flag(--limit/--tab/--filter…)不通用,看 <site> <command> --help。
环境变量
| 变量 | 默认 | 用途 |
|---|---|---|
OPENCLI_BROWSER_CONNECT_TIMEOUT |
45 |
等浏览器桥的秒数 |
OPENCLI_BROWSER_COMMAND_TIMEOUT |
60 |
单命令超时 |
OPENCLI_CDP_ENDPOINT |
- | 手动 CDP 端点(远程 Chrome / Electron) |
OPENCLI_CACHE_DIR |
~/.opencli/cache |
网络抓取 + 浏览器状态缓存 |
OPENCLI_CONFIG_DIR |
~/.opencli |
覆盖 opencli 配置目录(browser-profiles.json 等存这里) |
OPENCLI_WINDOW |
命令专属 | foreground / background 浏览器窗口模式 |
OPENCLI_PROFILE |
- | 路由到指定 Chrome profile 别名(见「§profile 路由」) |
OPENCLI_VERBOSE |
false |
详细日志(-v 也触发) |
profile 路由
opencli 的 "profile" 不是 Chrome 的 user profile,而是扩展自己生成的 8 位随机 contextId,每装一次扩展生成一个。
opencli profile list # 当前运行 + 连着的 context
opencli profile rename <contextId> bot # 给 context 起好记的别名
opencli profile use <alias> # 设默认 profile(软偏好,离线时回落到唯一连着的)
OPENCLI_PROFILE=bot opencli <site> <cmd> # 显式路由(离线会大声报错)
无人值守/自动化走专用 bot profile,隔离误操作;交互式留在默认 profile。
§浏览器原语核心
适配器没覆盖时,用 opencli browser * 临时驱动。完整原语手册见 references/browser.md,这里只放核心决策规则。
前置
opencli doctor # 没绿啥都干不了
会话生命周期
opencli browser *命令在browser后接一个<session>位置参数。多步流程用同一 session 名;隔离并行工作用不同名。- 临时会话:
opencli browser <session> open <url>...opencli browser <session> close。 - 绑定已开标签:
opencli browser <session> bind(用户已登录/已定位的标签)。 --window foreground|background控制是否前台聚焦窗口。
四条心智模型
- target 优先用数字 ref。 每个交互命令(
click/type/select/get)接一个<target>,是state/find输出的[N]数字 ref 或 CSS 选择器。CSS 多匹配时用--nth <n>消歧。 - 每个信封都报
matches_n和match_level。match_level是exact/stable/reidentified- CLI 已经替你救了中度 DOM 漂移,level 告诉你该多信。 - 紧凑输出优先,完整 payload 按需取。
state是预算快照;get html --as json支持--depth/--children-max/--text-max;network返回 shape 预览,用--detail <key>取单个 body。 - 结构化错误可机读。 失败时输出
{error: {code, message, hint?, candidates?}},按code分支,别按 message 字符串。
match_level 速查
| level | 含义 | 你该 |
|---|---|---|
exact |
指纹完全对上 | 继续 |
stable |
强 ID 还在,软信号(aria-label/role/text)漂了 | 继续;若写操作内容重要,get value 复查 |
reidentified |
原 ref 没了,CLI 找到唯一替代重新打了旧 ref | 复查是不是对的元素再继续 |
十条关键规则
- 先看后动。 先
state或find,别跨会话记 ref/选择器(索引是按快照的)。 - 优先站点适配器,别上来就裸开浏览器。
opencli <site> <command>能覆盖就用,opencli browser ...只补缺口。 - 拿到 ref 后优先用数字 ref。 ref 比 CSS 抗 DOM 漂移。
- 每次写操作后读
match_level。exact没事;stable内容重要就复查;reidentified必查。 - 表单控件用
compound字段。 别正则猜日期格式,别state两次取<select>选项列表。 - 写操作要验证。
type后跑get value;select后跑get value。自动补全/React 受控输入/掩码字段会静默吃字符,CLI 检测不到。 - 页面变化后
state-> action ->state。 导航/表单提交/SPA 路由会让 ref 失效,重新快照。 - 复用刚解析的 ref 时用
&&串联。 串联在一个 shell 里跑,ref 能直接传给下一条命令。 eval只读。 JS 包 IIFE 返回 JSON;要改页面用click/type/select/keys,它们产结构化输出和指纹,eval不产。- 优先
network而非屏幕抓取。 页面数据来自 JSON API 时,API 比抓 DOM 可靠得多。
常用命令速查
| 命令 | 用途 |
|---|---|
browser state |
快照:文本树 + [N] ref + compounds (N): 边栏 |
browser state --source ax |
无障碍树快照(自定义控件/portal/iframe 用) |
browser find --css <sel> |
CSS 查询,比 state 便宜 |
browser find --role button --name Save |
语义定位查询 |
browser click/type/select <target> |
交互(返回 match_level) |
browser get text/value/attributes <target> |
读单字段 |
browser network |
API shape 预览 + 缓存 key 列表 |
browser network --detail <key> |
取单个 cached body |
browser frames |
列跨域 iframe target,索引喂给 eval --frame |
browser extract |
长文 Markdown 抽取(带 next_start_char 游标) |
browser eval <js> |
页面内只读 JS |
browser wait selector/text/download |
等条件 |
browser tab list/new/select/close |
标签管理 |
browser <session> bind/unbind |
绑/解当前标签 |
browser screenshot --annotate |
可视化 ref 地图(图标控件/图表用) |
结构化错误码(按 code 分支,别按 message)
| code | 含义 |
|---|---|
not_found |
数字 ref 不在 DOM 了,重新 state |
stale_ref |
ref 在但元素变了身份,重新 state |
invalid_selector |
CSS 被 querySelectorAll 拒了 |
selector_not_found |
CSS 匹配 0 个,用 find 换更松的选择器 |
selector_ambiguous |
CSS 匹配 >1 且没 --nth |
selector_nth_out_of_range |
--nth 超出匹配数 |
option_not_found |
select 没找到选项,信封含 available: string[] |
完整命令参考、compound 表单控件、cost guide、recipes、pitfalls 见 references/browser.md。
§适配器失效自动修复
opencli <site> <command> 因网站改版失败时,别只报错,自动诊断 + 修适配器 + 重试。完整流程见 references/autofix.md,这里放关键边界。
硬停(不修代码)
AUTH_REQUIRED(exit 77)- 停。告诉用户去 Chrome 登录站点。BROWSER_CONNECT(exit 69)- 停。告诉用户跑opencli doctor。- CAPTCHA / 限频 - 停,不是适配器问题。
"空" ≠ "坏了"
EMPTY_RESULT 常常不是适配器 bug:平台反爬降级、软 404(HTTP 200 + 空 payload)、搜索"0 结果"是合法答案。修前先:
- 换查询或入口重试(
search "X"空但search "X 攻略"满 = 适配器没坏) - 正常 Chrome 标签里肉眼看一眼数据在不在
- 隔 2-3 秒重试区分"临时隐藏"和"真没了"
只有空/缺结果跨重试和替代入口都能复现,才进修复流程。
修复流程(最多 3 轮)
- 收 trace:
opencli <site> <cmd> [args] --trace retain-on-failure 2>trace-error.yaml,读 stderr 里的trace.summaryPath。 - 分析:读
summary.md(含adapterSourcePathfront matter)+ 适配器源码,按错误码归类(SELECTOR/EMPTY_RESULT/API_ERROR/TIMEOUT/PAGE_CHANGED)。 - 探活站:用
opencli browser <session> state/network看当前真实 DOM/API,别用坏掉的适配器。 - 打补丁:只改
adapterSourcePath指向的那一个文件,最小改动,保持columns输出结构,优先 API over DOM,只用@jackwener/opencli/*import。 - 验证:重跑
opencli <site> <cmd>,还失败回第 1 步取新 trace。3 轮耗尽就停并报告。 - 报上游:验证通过后,本地适配器已偏离 upstream,按模板起 GitHub issue,问用户确认后再用
gh issue create --repo jackwener/OpenCLI提交。
完整步骤、常见修复模式、issue 模板见 references/autofix.md。
§智能搜索路由
用户要搜索/查询/查找/研究信息时,按话题和场景把查询路由到最佳 opencli 搜索源。核心不是记命令,而是先定位数据源,再用 opencli ... -h 读实时帮助,避免文档漂移。
强制预检(每次都要做)
选定站点前:
opencli list -f yaml用 live registry 确认候选站点存在,检查strategy/browser/domain
选定站点后:
opencli <site> -h看子命令- 锁定子命令后再
opencli <site> <command> -h看参数/输出列/策略
别在 skill 里硬编码参数或假设命令签名,以 -h 实时输出为准。
主路由规则
- 用户明确指定网站/平台/数据源 -> 直接用对应站点。
- 用户没指定网站 -> 优先只选一个 AI 源:
grok/doubao/gemini三选一。 - AI 返回不足 / 缺原始数据 / 需权威佐证 / 需垂直结果 -> 再补 1-2 个专用源。
AI 源选择
grok- 实时讨论、英文舆论、Twitter/X 语境、热点追踪doubao- 中文语境、字节抖音生态、生活方式、中文热点gemini- 全球网页、英文资料、通用检索、背景综述
没指定网站时,先判语言语境,从这三选一。同一题内每个 AI 站点最多调 1 次,别反复追打。
单题预算
opencli list -f yaml、-h类帮助不计入搜索次数- 一次真正的
opencli <site> ...执行 = 该站点 1 次调用(失败也算) - AI 站点:同题内每站最多 1 次
- 非 AI 站点:默认最多 2 次;第 2 次必须有明确理由(第一次过宽要加时间/地区/类别/关键词限定);不要第 3 次
- 限频后:记录"已跳过: 达到频率上限",换同类站点或基于已收集信息回答并说明缺口
查询词构造(AI 源)
别只丢短关键词,构造"主题 + 目标 + 限定条件":<主题> + <你要回答的问题> / <主题> + <时间/地区/语言> / <主题> + <平台范围> / <主题> + <输出要求>。
查询结束汇报
回答末尾追加"搜索摘要":
搜索摘要
- 网站:<site1> | 查询词:<term1> | 次数:<n>
- 网站:<site2> | 查询词:<term2>;<term3> | 次数:<n>
- 已跳过:<site3>,原因:达到频率上限
各垂直源(技术/社交/媒体/资讯/购物/旅游等)的分类清单见 references/search/sources-*.md,按需读对应文件。
完整搜索路由规则、单题预算与频率限制、AI 查询词构造、查询结束汇报模板见 references/smart-search.md。
§写自己的适配器
要给新站点写适配器、或给现有站点加命令,读 references/adapter-author.md 走完整 runbook(从侦察到 opencli browser verify 闭环)。关键约定:
- 私人适配器放
~/.opencli/clis/<site>/<name>.js(免 build);要提 PR 才 copy 到clis/<site>/ - 只 import
@jackwener/opencli/registry+@jackwener/opencli/errors columns数组和func返回对象 keys 完全对齐(含顺序)browser:field 决定 func 签名:browser:false -> (args),browser:true -> (page, args)- 已知失败按 typed error 分类抛,别 silent
return []或 sentinel row - 调试原始 dump/抓包只短暂落
/tmp/或受控 cache,任务结束清理;通过数据分级的长期样本才进~/.opencli/sites/<site>/fixtures/。例外:JSDOM 单测 fixture 冻结在clis/<site>/__fixtures__/(有意 commit 的 review artifact),严禁 repo 根/工作目录留.dbg-*.html / raw-*.json
strategy 选择(PUBLIC_API/COOKIE_API/PAGE_FETCH/INTERCEPT/DOM_STATE/UI_SELECTOR)、字段解码、site-memory 回写等细节见 references/adapter/ 下对应文件。
适配器管理命令
opencli adapter status # 看哪些站点有本地覆盖 vs 用官方基线
opencli adapter eject <site> # 把官方适配器 copy 到 ~/.opencli/clis/ 供本地编辑
opencli adapter reset [site] # 删本地覆盖,恢复官方版本
opencli validate [target] # 语义检查注册表(description/domain/pipeline/args 等),无网络
opencli verify [target] [--smoke] # 验证 + 冒烟测试
opencli browser verify <site>/<name> # 在浏览器桥里端到端冒烟(init/verify 不需要 session)
§用 sitemap 驱动 / 写 sitemap
opencli browser <session> open 或 analyze 报 sitemap.available: true 时,读 references/browser-sitemap.md 用 sitemap 指导多步流程。sitemap 是先验知识不是真相,浏览器实状态和 sitemap 冲突时信浏览器。
要创建/维护站点 sitemap,读 references/sitemap-author.md(schema 细节见 references/sitemap/sitemap-schema.md)。
§外部 CLI 透传 / 插件
opencli external install gh # 按 external-clis.yaml 自动装
opencli external register my-tool --binary my-tool --install "npm i -g my-tool" --desc "..."
opencli external list [-f json] # 看已注册的外部 CLI
opencli gh pr list --limit 5 # 透传,stdio 继承,exit code 透传
opencli plugin install github:user/repo # 装插件
opencli plugin list [-f json] # 看已装
opencli plugin update [name] | --all # 更新
opencli plugin uninstall <name> # 卸载
opencli plugin create <name> # 脚手架生成新插件
内置 external 在 src/external-clis.yaml,用户覆盖在 ~/.opencli/external-clis.yaml。常见内置:gh、docker、vercel、lark-cli、longbridge、dws、wecom-cli、obsidian、ntn、tg、discord、wx。无 install 配置的条目(如 ntn,官方用 shell 安装器)需先手动装好才能透传。
已废弃命令(别再调)
以下在 PR #1094 合并被移除:
opencli explore <url>- 用opencli browser <session> network+find替代opencli record <url>- 用opencli browser <session> network --detail替代opencli web read/opencli desktop *作为顶层命令组 - 已并入各自适配器(opencli web read仍作为web适配器的read子命令存在,但没有独立的web/desktop顶层命令组)
红线
- 别把这个 skill 的命令列表贴进计划,会 rot。任务开始时跑
opencli list -f json。 - 别假设每个适配器都需要浏览器 -
public和local不需要,看strategy字段。 - 别把失败适配器静默回退到手写
fetch- 先--trace retain-on-failure取浏览器证据和适配器源路径。 - 别为了 "API-first" 把稳定的 UI/DOM 实现盲目迁到无契约内部接口(
PAGE_FETCH/INTERCEPT的 fix 频率约PUBLIC_API的 7-8 倍)。 - 写操作默认先确认再执行(发帖/回复/删除等)。