@jackwener/opencli 1.5.4 → 1.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -2
- package/README.zh-CN.md +36 -4
- package/dist/browser/daemon-client.d.ts +5 -1
- package/dist/browser/page.d.ts +6 -0
- package/dist/browser/page.js +15 -0
- package/dist/cli-manifest.json +1284 -67
- package/dist/cli.js +14 -14
- package/dist/clis/antigravity/serve.js +2 -2
- package/dist/clis/band/bands.d.ts +1 -0
- package/dist/clis/band/bands.js +72 -0
- package/dist/clis/band/mentions.d.ts +1 -0
- package/dist/clis/band/mentions.js +127 -0
- package/dist/clis/band/post.d.ts +1 -0
- package/dist/clis/band/post.js +175 -0
- package/dist/clis/band/posts.d.ts +1 -0
- package/dist/clis/band/posts.js +94 -0
- package/dist/clis/doubao/detail.d.ts +1 -0
- package/dist/clis/doubao/detail.js +33 -0
- package/dist/clis/doubao/detail.test.d.ts +1 -0
- package/dist/clis/doubao/detail.test.js +42 -0
- package/dist/clis/doubao/history.d.ts +1 -0
- package/dist/clis/doubao/history.js +28 -0
- package/dist/clis/doubao/history.test.d.ts +1 -0
- package/dist/clis/doubao/history.test.js +37 -0
- package/dist/clis/doubao/meeting-summary.d.ts +1 -0
- package/dist/clis/doubao/meeting-summary.js +39 -0
- package/dist/clis/doubao/meeting-transcript.d.ts +1 -0
- package/dist/clis/doubao/meeting-transcript.js +36 -0
- package/dist/clis/doubao/utils.d.ts +27 -0
- package/dist/clis/doubao/utils.js +317 -0
- package/dist/clis/doubao/utils.test.d.ts +1 -0
- package/dist/clis/doubao/utils.test.js +24 -0
- package/dist/clis/douyin/_shared/public-api.d.ts +33 -0
- package/dist/clis/douyin/_shared/public-api.js +29 -0
- package/dist/clis/douyin/user-videos.d.ts +5 -0
- package/dist/clis/douyin/user-videos.js +74 -0
- package/dist/clis/douyin/user-videos.test.d.ts +1 -0
- package/dist/clis/douyin/user-videos.test.js +108 -0
- package/dist/clis/ones/common.d.ts +32 -0
- package/dist/clis/ones/common.js +144 -0
- package/dist/clis/ones/enrich-tasks.d.ts +5 -0
- package/dist/clis/ones/enrich-tasks.js +37 -0
- package/dist/clis/ones/login.d.ts +1 -0
- package/dist/clis/ones/login.js +80 -0
- package/dist/clis/ones/logout.d.ts +1 -0
- package/dist/clis/ones/logout.js +17 -0
- package/dist/clis/ones/me.d.ts +1 -0
- package/dist/clis/ones/me.js +30 -0
- package/dist/clis/ones/my-tasks.d.ts +1 -0
- package/dist/clis/ones/my-tasks.js +120 -0
- package/dist/clis/ones/resolve-labels.d.ts +10 -0
- package/dist/clis/ones/resolve-labels.js +64 -0
- package/dist/clis/ones/task-helpers.d.ts +29 -0
- package/dist/clis/ones/task-helpers.js +212 -0
- package/dist/clis/ones/task-helpers.test.d.ts +1 -0
- package/dist/clis/ones/task-helpers.test.js +12 -0
- package/dist/clis/ones/task.d.ts +1 -0
- package/dist/clis/ones/task.js +66 -0
- package/dist/clis/ones/tasks.d.ts +1 -0
- package/dist/clis/ones/tasks.js +79 -0
- package/dist/clis/ones/token-info.d.ts +1 -0
- package/dist/clis/ones/token-info.js +42 -0
- package/dist/clis/ones/worklog.d.ts +11 -0
- package/dist/clis/ones/worklog.js +267 -0
- package/dist/clis/ones/worklog.test.d.ts +1 -0
- package/dist/clis/ones/worklog.test.js +20 -0
- package/dist/clis/sinafinance/rolling-news.d.ts +4 -0
- package/dist/clis/sinafinance/rolling-news.js +40 -0
- package/dist/clis/sinafinance/stock.d.ts +8 -0
- package/dist/clis/sinafinance/stock.js +117 -0
- package/dist/clis/spotify/spotify.d.ts +1 -0
- package/dist/clis/spotify/spotify.js +316 -0
- package/dist/clis/spotify/utils.d.ts +21 -0
- package/dist/clis/spotify/utils.js +66 -0
- package/dist/clis/spotify/utils.test.d.ts +1 -0
- package/dist/clis/spotify/utils.test.js +67 -0
- package/dist/clis/tieba/commands.test.d.ts +4 -0
- package/dist/clis/tieba/commands.test.js +79 -0
- package/dist/clis/tieba/hot.d.ts +1 -0
- package/dist/clis/tieba/hot.js +48 -0
- package/dist/clis/tieba/posts.d.ts +1 -0
- package/dist/clis/tieba/posts.js +85 -0
- package/dist/clis/tieba/read.d.ts +1 -0
- package/dist/clis/tieba/read.js +140 -0
- package/dist/clis/tieba/search.d.ts +1 -0
- package/dist/clis/tieba/search.js +108 -0
- package/dist/clis/tieba/utils.d.ts +101 -0
- package/dist/clis/tieba/utils.js +240 -0
- package/dist/clis/tieba/utils.test.d.ts +1 -0
- package/dist/clis/tieba/utils.test.js +290 -0
- package/dist/clis/weread/book.js +100 -13
- package/dist/clis/weread/commands.test.js +221 -0
- package/dist/clis/weread/private-api-regression.test.d.ts +1 -0
- package/dist/{weread-private-api-regression.test.js → clis/weread/private-api-regression.test.js} +92 -30
- package/dist/clis/weread/search-regression.test.d.ts +1 -0
- package/dist/clis/weread/search-regression.test.js +407 -0
- package/dist/clis/weread/search.js +143 -7
- package/dist/clis/weread/shelf.js +13 -95
- package/dist/clis/weread/utils.d.ts +46 -0
- package/dist/clis/weread/utils.js +214 -7
- package/dist/clis/weread/utils.test.js +71 -1
- package/dist/clis/xiaohongshu/publish.d.ts +1 -1
- package/dist/clis/xiaohongshu/publish.js +78 -31
- package/dist/clis/xiaohongshu/publish.test.js +66 -1
- package/dist/clis/xiaohongshu/user-helpers.d.ts +1 -0
- package/dist/clis/xiaohongshu/user-helpers.js +2 -0
- package/dist/clis/xiaohongshu/user-helpers.test.js +18 -0
- package/dist/clis/xueqiu/comments.d.ts +118 -0
- package/dist/clis/xueqiu/comments.js +354 -0
- package/dist/clis/xueqiu/comments.test.d.ts +1 -0
- package/dist/clis/xueqiu/comments.test.js +696 -0
- package/dist/clis/youtube/transcript.js +2 -4
- package/dist/clis/youtube/utils.d.ts +9 -0
- package/dist/clis/youtube/utils.js +67 -3
- package/dist/clis/youtube/utils.test.d.ts +1 -0
- package/dist/clis/youtube/utils.test.js +37 -0
- package/dist/clis/youtube/video.js +16 -15
- package/dist/clis/zsxq/dynamics.d.ts +1 -0
- package/dist/clis/zsxq/dynamics.js +47 -0
- package/dist/clis/zsxq/groups.d.ts +1 -0
- package/dist/clis/zsxq/groups.js +32 -0
- package/dist/clis/zsxq/search.d.ts +1 -0
- package/dist/clis/zsxq/search.js +43 -0
- package/dist/clis/zsxq/search.test.d.ts +1 -0
- package/dist/clis/zsxq/search.test.js +24 -0
- package/dist/clis/zsxq/topic.d.ts +1 -0
- package/dist/clis/zsxq/topic.js +47 -0
- package/dist/clis/zsxq/topic.test.d.ts +1 -0
- package/dist/clis/zsxq/topic.test.js +29 -0
- package/dist/clis/zsxq/topics.d.ts +1 -0
- package/dist/clis/zsxq/topics.js +25 -0
- package/dist/clis/zsxq/topics.test.d.ts +1 -0
- package/dist/clis/zsxq/topics.test.js +24 -0
- package/dist/clis/zsxq/utils.d.ts +97 -0
- package/dist/clis/zsxq/utils.js +230 -0
- package/dist/commanderAdapter.js +27 -4
- package/dist/commanderAdapter.test.js +39 -0
- package/dist/daemon.js +5 -4
- package/dist/errors.d.ts +29 -1
- package/dist/errors.js +49 -11
- package/dist/external-clis.yaml +17 -0
- package/dist/external.js +3 -3
- package/dist/main.js +2 -1
- package/dist/tui.js +2 -1
- package/dist/types.d.ts +5 -0
- package/docs/.vitepress/config.mts +3 -0
- package/docs/adapters/browser/band.md +63 -0
- package/docs/adapters/browser/ones.md +59 -0
- package/docs/adapters/browser/sinafinance.md +56 -6
- package/docs/adapters/browser/spotify.md +62 -0
- package/docs/adapters/browser/tieba.md +45 -0
- package/docs/adapters/browser/xueqiu.md +5 -0
- package/docs/adapters/browser/zsxq.md +49 -0
- package/docs/adapters/index.md +5 -2
- package/docs/adapters-doc/ones.md +32 -0
- package/extension/dist/background.js +1 -2
- package/extension/manifest.json +1 -1
- package/extension/package.json +1 -1
- package/extension/src/background.ts +17 -1
- package/extension/src/cdp.ts +42 -0
- package/extension/src/protocol.ts +5 -1
- package/package.json +1 -1
- package/scripts/postinstall.js +16 -0
- package/src/browser/daemon-client.ts +5 -1
- package/src/browser/page.ts +16 -0
- package/src/cli.ts +14 -14
- package/src/clis/antigravity/serve.ts +2 -2
- package/src/clis/band/bands.ts +76 -0
- package/src/clis/band/mentions.ts +134 -0
- package/src/clis/band/post.ts +187 -0
- package/src/clis/band/posts.ts +106 -0
- package/src/clis/doubao/detail.test.ts +53 -0
- package/src/clis/doubao/detail.ts +41 -0
- package/src/clis/doubao/history.test.ts +45 -0
- package/src/clis/doubao/history.ts +32 -0
- package/src/clis/doubao/meeting-summary.ts +53 -0
- package/src/clis/doubao/meeting-transcript.ts +48 -0
- package/src/clis/doubao/utils.test.ts +45 -0
- package/src/clis/doubao/utils.ts +371 -0
- package/src/clis/douyin/_shared/public-api.ts +84 -0
- package/src/clis/douyin/user-videos.test.ts +122 -0
- package/src/clis/douyin/user-videos.ts +101 -0
- package/src/clis/ones/common.ts +187 -0
- package/src/clis/ones/enrich-tasks.ts +47 -0
- package/src/clis/ones/login.ts +103 -0
- package/src/clis/ones/logout.ts +19 -0
- package/src/clis/ones/me.ts +34 -0
- package/src/clis/ones/my-tasks.ts +148 -0
- package/src/clis/ones/resolve-labels.ts +80 -0
- package/src/clis/ones/task-helpers.test.ts +14 -0
- package/src/clis/ones/task-helpers.ts +214 -0
- package/src/clis/ones/task.ts +79 -0
- package/src/clis/ones/tasks.ts +92 -0
- package/src/clis/ones/token-info.ts +46 -0
- package/src/clis/ones/worklog.test.ts +24 -0
- package/src/clis/ones/worklog.ts +306 -0
- package/src/clis/sinafinance/rolling-news.ts +42 -0
- package/src/clis/sinafinance/stock.ts +127 -0
- package/src/clis/spotify/spotify.ts +328 -0
- package/src/clis/spotify/utils.test.ts +87 -0
- package/src/clis/spotify/utils.ts +92 -0
- package/src/clis/tieba/commands.test.ts +86 -0
- package/src/clis/tieba/hot.ts +52 -0
- package/src/clis/tieba/posts.ts +108 -0
- package/src/clis/tieba/read.ts +158 -0
- package/src/clis/tieba/search.ts +119 -0
- package/src/clis/tieba/utils.test.ts +322 -0
- package/src/clis/tieba/utils.ts +348 -0
- package/src/clis/weread/book.ts +116 -13
- package/src/clis/weread/commands.test.ts +249 -0
- package/src/{weread-private-api-regression.test.ts → clis/weread/private-api-regression.test.ts} +108 -30
- package/src/clis/weread/search-regression.test.ts +440 -0
- package/src/clis/weread/search.ts +189 -9
- package/src/clis/weread/shelf.ts +20 -122
- package/src/clis/weread/utils.test.ts +81 -1
- package/src/clis/weread/utils.ts +264 -7
- package/src/clis/xiaohongshu/publish.test.ts +79 -1
- package/src/clis/xiaohongshu/publish.ts +84 -30
- package/src/clis/xiaohongshu/user-helpers.test.ts +23 -0
- package/src/clis/xiaohongshu/user-helpers.ts +4 -0
- package/src/clis/xueqiu/comments.test.ts +823 -0
- package/src/clis/xueqiu/comments.ts +461 -0
- package/src/clis/youtube/transcript.ts +2 -4
- package/src/clis/youtube/utils.test.ts +43 -0
- package/src/clis/youtube/utils.ts +69 -0
- package/src/clis/youtube/video.ts +16 -15
- package/src/clis/zsxq/dynamics.ts +60 -0
- package/src/clis/zsxq/groups.ts +41 -0
- package/src/clis/zsxq/search.test.ts +29 -0
- package/src/clis/zsxq/search.ts +54 -0
- package/src/clis/zsxq/topic.test.ts +34 -0
- package/src/clis/zsxq/topic.ts +68 -0
- package/src/clis/zsxq/topics.test.ts +29 -0
- package/src/clis/zsxq/topics.ts +36 -0
- package/src/clis/zsxq/utils.ts +351 -0
- package/src/commanderAdapter.test.ts +47 -0
- package/src/commanderAdapter.ts +26 -3
- package/src/daemon.ts +5 -4
- package/src/errors.ts +71 -10
- package/src/external-clis.yaml +17 -0
- package/src/external.ts +3 -3
- package/src/main.ts +2 -1
- package/src/tui.ts +2 -1
- package/src/types.ts +5 -0
- package/tests/e2e/band-auth.test.ts +20 -0
- package/tests/e2e/browser-auth-helpers.ts +18 -0
- package/tests/e2e/browser-auth.test.ts +35 -47
- package/tests/e2e/browser-public.test.ts +288 -0
- package/tests/e2e/management.test.ts +1 -1
- package/tests/e2e/plugin-management.test.ts +1 -1
- package/vitest.config.ts +1 -0
- package/SKILL.md +0 -879
- package/dist/weread-private-api-regression.test.d.ts +0 -1
- package/dist/weread-search-regression.test.d.ts +0 -1
- package/dist/weread-search-regression.test.js +0 -39
- package/src/weread-search-regression.test.ts +0 -44
package/SKILL.md
DELETED
|
@@ -1,879 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: opencli
|
|
3
|
-
description: "OpenCLI — Make any website or Electron App your CLI. Zero risk, AI-powered, reuse Chrome login."
|
|
4
|
-
version: 1.4.1
|
|
5
|
-
author: jackwener
|
|
6
|
-
tags: [cli, browser, web, chrome-extension, cdp, bilibili, zhihu, twitter, github, v2ex, hackernews, reddit, xiaohongshu, xueqiu, youtube, boss, coupang, yollomi, AI, agent]
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# OpenCLI
|
|
10
|
-
|
|
11
|
-
> Make any website or Electron App your CLI. Reuse Chrome login, zero risk, AI-powered discovery.
|
|
12
|
-
|
|
13
|
-
> [!CAUTION]
|
|
14
|
-
> **AI Agent 必读:创建或修改任何适配器之前,你必须先阅读 [CLI-EXPLORER.md](./CLI-EXPLORER.md)!**
|
|
15
|
-
> 该文档包含完整的 API 发现工作流(必须使用浏览器探索)、5 级认证策略决策树、平台 SDK 速查表、`tap` 步骤调试流程、分页 API 模板、级联请求模式、以及常见陷阱。
|
|
16
|
-
> **本文件(SKILL.md)仅提供命令参考和简化模板,不足以正确开发适配器。**
|
|
17
|
-
|
|
18
|
-
> [!IMPORTANT]
|
|
19
|
-
> 创建或修改 adapter 时,再额外遵守 3 条收口规则:
|
|
20
|
-
> 1. 主参数优先用 positional arg,不要把 `query` / `id` / `url` 默认做成 `--query` / `--id` / `--url`
|
|
21
|
-
> 2. 预期中的 adapter 失败优先抛 `CliError` 子类,不要直接 throw 原始 `Error`
|
|
22
|
-
> 3. 新增 adapter 或新增用户可发现命令时,同步更新 adapter docs、`docs/adapters/index.md`、sidebar,以及 README/README.zh-CN 中受影响的入口
|
|
23
|
-
|
|
24
|
-
## Install & Run
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
# npm global install (recommended)
|
|
28
|
-
npm install -g @jackwener/opencli
|
|
29
|
-
opencli <command>
|
|
30
|
-
|
|
31
|
-
# Or from source
|
|
32
|
-
cd ~/code/opencli && npm install
|
|
33
|
-
npx tsx src/main.ts <command>
|
|
34
|
-
|
|
35
|
-
# Update to latest
|
|
36
|
-
npm update -g @jackwener/opencli
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Prerequisites
|
|
40
|
-
|
|
41
|
-
Browser commands require:
|
|
42
|
-
1. Chrome browser running **(logged into target sites)**
|
|
43
|
-
2. **opencli Browser Bridge** Chrome extension installed (load `extension/` as unpacked in `chrome://extensions`)
|
|
44
|
-
3. No further setup needed — the daemon auto-starts on first browser command
|
|
45
|
-
|
|
46
|
-
> **Note**: You must be logged into the target website in Chrome before running commands. Tabs opened during command execution are auto-closed afterwards.
|
|
47
|
-
|
|
48
|
-
Public API commands (`hackernews`, `v2ex`) need no browser.
|
|
49
|
-
|
|
50
|
-
## Commands Reference
|
|
51
|
-
|
|
52
|
-
### Data Commands
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
# Bilibili (browser)
|
|
56
|
-
opencli bilibili hot --limit 10 # B站热门视频
|
|
57
|
-
opencli bilibili search "rust" # 搜索视频 (query positional)
|
|
58
|
-
opencli bilibili me # 我的信息
|
|
59
|
-
opencli bilibili favorite # 我的收藏
|
|
60
|
-
opencli bilibili history --limit 20 # 观看历史
|
|
61
|
-
opencli bilibili feed --limit 10 # 动态时间线
|
|
62
|
-
opencli bilibili user-videos --uid 12345 # 用户投稿
|
|
63
|
-
opencli bilibili subtitle --bvid BV1xxx # 获取视频字幕 (支持 --lang zh-CN)
|
|
64
|
-
opencli bilibili dynamic --limit 10 # 动态
|
|
65
|
-
opencli bilibili ranking --limit 10 # 排行榜
|
|
66
|
-
opencli bilibili following --limit 20 # 我的关注列表 (支持 --uid 查看他人)
|
|
67
|
-
|
|
68
|
-
# 知乎 (browser)
|
|
69
|
-
opencli zhihu hot --limit 10 # 知乎热榜
|
|
70
|
-
opencli zhihu search "AI" # 搜索 (query positional)
|
|
71
|
-
opencli zhihu question 34816524 # 问题详情和回答 (id positional)
|
|
72
|
-
|
|
73
|
-
# 小红书 (browser)
|
|
74
|
-
opencli xiaohongshu search "美食" # 搜索笔记 (query positional)
|
|
75
|
-
opencli xiaohongshu notifications # 通知(mentions/likes/connections)
|
|
76
|
-
opencli xiaohongshu feed --limit 10 # 推荐 Feed
|
|
77
|
-
opencli xiaohongshu user xxx # 用户主页 (id positional)
|
|
78
|
-
opencli xiaohongshu creator-notes --limit 10 # 创作者笔记列表
|
|
79
|
-
opencli xiaohongshu creator-note-detail --note-id xxx # 笔记详情
|
|
80
|
-
opencli xiaohongshu creator-notes-summary # 笔记数据概览
|
|
81
|
-
opencli xiaohongshu creator-profile # 创作者资料
|
|
82
|
-
opencli xiaohongshu creator-stats # 创作者数据统计
|
|
83
|
-
|
|
84
|
-
# 雪球 Xueqiu (browser)
|
|
85
|
-
opencli xueqiu hot-stock --limit 10 # 雪球热门股票榜
|
|
86
|
-
opencli xueqiu stock --symbol SH600519 # 查看股票实时行情
|
|
87
|
-
opencli xueqiu watchlist # 获取自选股/持仓列表
|
|
88
|
-
opencli xueqiu feed # 我的关注 timeline
|
|
89
|
-
opencli xueqiu hot --limit 10 # 雪球热榜
|
|
90
|
-
opencli xueqiu search "特斯拉" # 搜索 (query positional)
|
|
91
|
-
opencli xueqiu earnings-date SH600519 # 股票财报发布日期 (symbol positional)
|
|
92
|
-
opencli xueqiu fund-holdings # 蛋卷基金持仓明细 (支持 --account 过滤)
|
|
93
|
-
opencli xueqiu fund-snapshot # 蛋卷基金快照(总资产、子账户、持仓)
|
|
94
|
-
|
|
95
|
-
# GitHub (via gh External CLI)
|
|
96
|
-
opencli gh repo list # 列出仓库 (passthrough to gh)
|
|
97
|
-
opencli gh pr list --limit 5 # PR 列表
|
|
98
|
-
opencli gh issue list # Issue 列表
|
|
99
|
-
|
|
100
|
-
# Twitter/X (browser)
|
|
101
|
-
opencli twitter trending --limit 10 # 热门话题
|
|
102
|
-
opencli twitter bookmarks --limit 20 # 获取收藏的书签推文
|
|
103
|
-
opencli twitter search "AI" # 搜索推文 (query positional)
|
|
104
|
-
opencli twitter profile elonmusk # 用户资料
|
|
105
|
-
opencli twitter timeline --limit 20 # 时间线
|
|
106
|
-
opencli twitter thread 1234567890 # 推文 thread(原文 + 回复)
|
|
107
|
-
opencli twitter article 1891511252174299446 # 推文长文内容
|
|
108
|
-
opencli twitter follow elonmusk # 关注用户
|
|
109
|
-
opencli twitter unfollow elonmusk # 取消关注
|
|
110
|
-
opencli twitter bookmark https://x.com/... # 收藏推文
|
|
111
|
-
opencli twitter unbookmark https://x.com/... # 取消收藏
|
|
112
|
-
opencli twitter post "Hello world" # 发布推文 (text positional)
|
|
113
|
-
opencli twitter like https://x.com/... # 点赞推文 (url positional)
|
|
114
|
-
opencli twitter reply https://x.com/... "Nice!" # 回复推文 (url + text positional)
|
|
115
|
-
opencli twitter delete https://x.com/... # 删除推文 (url positional)
|
|
116
|
-
opencli twitter block elonmusk # 屏蔽用户 (username positional)
|
|
117
|
-
opencli twitter unblock elonmusk # 取消屏蔽 (username positional)
|
|
118
|
-
opencli twitter followers elonmusk # 用户的粉丝列表 (user positional)
|
|
119
|
-
opencli twitter following elonmusk # 用户的关注列表 (user positional)
|
|
120
|
-
opencli twitter notifications --limit 20 # 通知列表
|
|
121
|
-
opencli twitter hide-reply https://x.com/... # 隐藏回复 (url positional)
|
|
122
|
-
opencli twitter download elonmusk # 下载用户媒体 (username positional, 支持 --tweet-url)
|
|
123
|
-
opencli twitter accept "群,微信" # 自动接受含关键词的 DM 请求 (query positional)
|
|
124
|
-
opencli twitter reply-dm "消息内容" # 批量回复 DM (text positional)
|
|
125
|
-
|
|
126
|
-
# Reddit (browser)
|
|
127
|
-
opencli reddit hot --limit 10 # 热门帖子
|
|
128
|
-
opencli reddit hot --subreddit programming # 指定子版块
|
|
129
|
-
opencli reddit frontpage --limit 10 # 首页 /r/all
|
|
130
|
-
opencli reddit popular --limit 10 # /r/popular 热门
|
|
131
|
-
opencli reddit search "AI" --sort top --time week # 搜索(支持排序+时间过滤)
|
|
132
|
-
opencli reddit subreddit rust --sort top --time month # 子版块浏览(支持时间过滤)
|
|
133
|
-
opencli reddit read --post-id 1abc123 # 阅读帖子 + 评论
|
|
134
|
-
opencli reddit user spez # 用户资料(karma、注册时间)
|
|
135
|
-
opencli reddit user-posts spez # 用户发帖历史
|
|
136
|
-
opencli reddit user-comments spez # 用户评论历史
|
|
137
|
-
opencli reddit upvote --post-id xxx --direction up # 投票(up/down/none)
|
|
138
|
-
opencli reddit save --post-id xxx # 收藏帖子
|
|
139
|
-
opencli reddit comment --post-id xxx "Great!" # 发表评论 (text positional)
|
|
140
|
-
opencli reddit subscribe --subreddit python # 订阅子版块
|
|
141
|
-
opencli reddit saved --limit 10 # 我的收藏
|
|
142
|
-
opencli reddit upvoted --limit 10 # 我的赞
|
|
143
|
-
|
|
144
|
-
# V2EX (public + browser)
|
|
145
|
-
opencli v2ex hot --limit 10 # 热门话题
|
|
146
|
-
opencli v2ex latest --limit 10 # 最新话题
|
|
147
|
-
opencli v2ex topic 1024 # 主题详情 (id positional)
|
|
148
|
-
opencli v2ex daily # 每日签到 (browser)
|
|
149
|
-
opencli v2ex me # 我的信息 (browser)
|
|
150
|
-
opencli v2ex notifications --limit 10 # 通知 (browser)
|
|
151
|
-
opencli v2ex node python # 节点话题列表 (name positional)
|
|
152
|
-
opencli v2ex nodes --limit 30 # 所有节点列表
|
|
153
|
-
opencli v2ex member username # 用户资料 (username positional)
|
|
154
|
-
opencli v2ex user username # 用户发帖列表 (username positional)
|
|
155
|
-
opencli v2ex replies 1024 # 主题回复列表 (id positional)
|
|
156
|
-
|
|
157
|
-
# Hacker News (public)
|
|
158
|
-
opencli hackernews top --limit 10 # Top stories
|
|
159
|
-
opencli hackernews new --limit 10 # Newest stories
|
|
160
|
-
opencli hackernews best --limit 10 # Best stories
|
|
161
|
-
opencli hackernews ask --limit 10 # Ask HN posts
|
|
162
|
-
opencli hackernews show --limit 10 # Show HN posts
|
|
163
|
-
opencli hackernews jobs --limit 10 # Job postings
|
|
164
|
-
opencli hackernews search "rust" # 搜索 (query positional)
|
|
165
|
-
opencli hackernews user dang # 用户资料 (username positional)
|
|
166
|
-
|
|
167
|
-
# BBC (public)
|
|
168
|
-
opencli bbc news --limit 10 # BBC News RSS headlines
|
|
169
|
-
|
|
170
|
-
# 微博 (browser)
|
|
171
|
-
opencli weibo hot --limit 10 # 微博热搜
|
|
172
|
-
|
|
173
|
-
# BOSS直聘 (browser)
|
|
174
|
-
opencli boss search "AI agent" # 搜索职位 (query positional)
|
|
175
|
-
opencli boss detail --security-id xxx # 职位详情
|
|
176
|
-
opencli boss recommend --limit 10 # 推荐职位
|
|
177
|
-
opencli boss joblist --limit 10 # 职位列表
|
|
178
|
-
opencli boss greet --security-id xxx # 打招呼
|
|
179
|
-
opencli boss batchgreet --job-id xxx # 批量打招呼
|
|
180
|
-
opencli boss send --uid xxx "消息内容" # 发消息 (text positional)
|
|
181
|
-
opencli boss chatlist --limit 10 # 聊天列表
|
|
182
|
-
opencli boss chatmsg --security-id xxx # 聊天记录
|
|
183
|
-
opencli boss invite --security-id xxx # 邀请沟通
|
|
184
|
-
opencli boss mark --security-id xxx # 标记管理
|
|
185
|
-
opencli boss exchange --security-id xxx # 交换联系方式
|
|
186
|
-
opencli boss resume # 简历管理
|
|
187
|
-
opencli boss stats # 数据统计
|
|
188
|
-
|
|
189
|
-
# YouTube (browser)
|
|
190
|
-
opencli youtube search "rust" # 搜索视频 (query positional)
|
|
191
|
-
opencli youtube video "https://www.youtube.com/watch?v=xxx" # 视频元数据
|
|
192
|
-
opencli youtube transcript "https://www.youtube.com/watch?v=xxx" # 获取视频字幕/转录
|
|
193
|
-
opencli youtube transcript "xxx" --lang zh-Hans --mode raw # 指定语言 + 原始时间戳模式
|
|
194
|
-
|
|
195
|
-
# Yahoo Finance (browser)
|
|
196
|
-
opencli yahoo-finance quote --symbol AAPL # 股票行情
|
|
197
|
-
|
|
198
|
-
# Sina Finance
|
|
199
|
-
opencli sinafinance news --limit 10 --type 1 # 7x24实时快讯 (0=全部 1=A股 2=宏观 3=公司 4=数据 5=市场 6=国际 7=观点 8=央行 9=其它)
|
|
200
|
-
|
|
201
|
-
# Reuters (browser)
|
|
202
|
-
opencli reuters search "AI" # 路透社搜索 (query positional)
|
|
203
|
-
|
|
204
|
-
# 什么值得买 (browser)
|
|
205
|
-
opencli smzdm search "耳机" # 搜索好价 (query positional)
|
|
206
|
-
|
|
207
|
-
# 携程 (browser)
|
|
208
|
-
opencli ctrip search "三亚" # 搜索目的地 (query positional)
|
|
209
|
-
|
|
210
|
-
# Antigravity (Electron/CDP)
|
|
211
|
-
opencli antigravity status # 检查 CDP 连接
|
|
212
|
-
opencli antigravity send "hello" # 发送文本到当前 agent 聊天框
|
|
213
|
-
opencli antigravity read # 读取整个聊天记录面板
|
|
214
|
-
opencli antigravity new # 清空聊天、开启新对话
|
|
215
|
-
opencli antigravity dump # 导出 DOM 和快照调试信息
|
|
216
|
-
opencli antigravity extract-code # 自动抽取 AI 回复中的代码块
|
|
217
|
-
opencli antigravity model claude # 切换底层模型
|
|
218
|
-
opencli antigravity watch # 流式监听增量消息
|
|
219
|
-
|
|
220
|
-
# Barchart (browser)
|
|
221
|
-
opencli barchart quote --symbol AAPL # 股票行情
|
|
222
|
-
opencli barchart options --symbol AAPL # 期权链
|
|
223
|
-
opencli barchart greeks --symbol AAPL # 期权 Greeks
|
|
224
|
-
opencli barchart flow --limit 20 # 异常期权活动
|
|
225
|
-
|
|
226
|
-
# Jike 即刻 (browser)
|
|
227
|
-
opencli jike feed --limit 10 # 动态流
|
|
228
|
-
opencli jike search "AI" # 搜索 (query positional)
|
|
229
|
-
opencli jike create "内容" # 发布动态 (text positional)
|
|
230
|
-
opencli jike like xxx # 点赞 (id positional)
|
|
231
|
-
opencli jike comment xxx "评论" # 评论 (id + text positional)
|
|
232
|
-
opencli jike repost xxx # 转发 (id positional)
|
|
233
|
-
opencli jike notifications # 通知
|
|
234
|
-
|
|
235
|
-
# Linux.do (public + browser)
|
|
236
|
-
opencli linux-do hot --limit 10 # 热门话题
|
|
237
|
-
opencli linux-do latest --limit 10 # 最新话题
|
|
238
|
-
opencli linux-do search "rust" # 搜索 (query positional)
|
|
239
|
-
opencli linux-do topic 1024 # 主题详情 (id positional)
|
|
240
|
-
opencli linux-do categories --limit 20 # 分类列表 (browser)
|
|
241
|
-
opencli linux-do category dev 7 # 分类内话题 (slug + id positional, browser)
|
|
242
|
-
|
|
243
|
-
# StackOverflow (public)
|
|
244
|
-
opencli stackoverflow hot --limit 10 # 热门问题
|
|
245
|
-
opencli stackoverflow search "typescript" # 搜索 (query positional)
|
|
246
|
-
opencli stackoverflow bounties --limit 10 # 悬赏问题
|
|
247
|
-
|
|
248
|
-
# WeRead 微信读书 (browser)
|
|
249
|
-
opencli weread shelf --limit 10 # 书架
|
|
250
|
-
opencli weread search "AI" # 搜索图书 (query positional)
|
|
251
|
-
opencli weread book xxx # 图书详情 (book-id positional)
|
|
252
|
-
opencli weread highlights xxx # 划线笔记 (book-id positional)
|
|
253
|
-
opencli weread notes xxx # 想法笔记 (book-id positional)
|
|
254
|
-
opencli weread ranking --limit 10 # 排行榜
|
|
255
|
-
|
|
256
|
-
# Jimeng 即梦 AI (browser)
|
|
257
|
-
opencli jimeng generate --prompt "描述" # AI 生图
|
|
258
|
-
opencli jimeng history --limit 10 # 生成历史
|
|
259
|
-
|
|
260
|
-
# Yollomi yollomi.com (browser — 需在 Chrome 登录 yollomi.com,复用站点 session)
|
|
261
|
-
opencli yollomi models --type image # 列出图像模型与积分
|
|
262
|
-
opencli yollomi generate "提示词" --model z-image-turbo # 文生图
|
|
263
|
-
opencli yollomi video "提示词" --model kling-2-1 # 视频
|
|
264
|
-
opencli yollomi upload ./photo.jpg # 上传得 URL,供 img2img / 工具链使用
|
|
265
|
-
opencli yollomi remove-bg <image-url> # 去背景(免费)
|
|
266
|
-
opencli yollomi edit <image-url> "改成油画风格" # Qwen 图像编辑
|
|
267
|
-
opencli yollomi background <image-url> # AI 背景生成 (5 credits)
|
|
268
|
-
opencli yollomi face-swap --source <url> --target <url> # 换脸 (3 credits)
|
|
269
|
-
opencli yollomi object-remover <image-url> <mask-url> # AI 去除物体 (3 credits)
|
|
270
|
-
opencli yollomi restore <image-url> # AI 修复老照片 (4 credits)
|
|
271
|
-
opencli yollomi try-on --person <url> --cloth <url> # 虚拟试衣 (3 credits)
|
|
272
|
-
opencli yollomi upscale <image-url> # AI 超分辨率 (1 credit, 支持 --scale 2/4)
|
|
273
|
-
|
|
274
|
-
# Grok (default + explicit web)
|
|
275
|
-
opencli grok ask --prompt "问题" # 提问 Grok(兼容默认路径)
|
|
276
|
-
opencli grok ask --prompt "问题" --web # 显式 grok.com consumer web UI 路径
|
|
277
|
-
|
|
278
|
-
# HuggingFace (public)
|
|
279
|
-
opencli hf top --limit 10 # 热门模型
|
|
280
|
-
|
|
281
|
-
# 超星学习通 (browser)
|
|
282
|
-
opencli chaoxing assignments # 作业列表
|
|
283
|
-
opencli chaoxing exams # 考试列表
|
|
284
|
-
|
|
285
|
-
# Douban 豆瓣 (browser)
|
|
286
|
-
opencli douban search "三体" # 搜索 (query positional)
|
|
287
|
-
opencli douban top250 # 豆瓣 Top 250
|
|
288
|
-
opencli douban subject 1234567 # 条目详情 (id positional)
|
|
289
|
-
opencli douban photos 30382501 # 图片列表 / 直链(默认海报)
|
|
290
|
-
opencli douban download 30382501 # 下载海报 / 剧照
|
|
291
|
-
opencli douban marks --limit 10 # 我的标记
|
|
292
|
-
opencli douban reviews --limit 10 # 短评
|
|
293
|
-
|
|
294
|
-
# Facebook (browser)
|
|
295
|
-
opencli facebook feed --limit 10 # 动态流
|
|
296
|
-
opencli facebook profile username # 用户资料 (id positional)
|
|
297
|
-
opencli facebook search "AI" # 搜索 (query positional)
|
|
298
|
-
opencli facebook friends # 好友列表
|
|
299
|
-
opencli facebook groups # 群组
|
|
300
|
-
opencli facebook events # 活动
|
|
301
|
-
opencli facebook notifications # 通知
|
|
302
|
-
opencli facebook memories # 回忆
|
|
303
|
-
opencli facebook add-friend username # 添加好友 (id positional)
|
|
304
|
-
opencli facebook join-group groupid # 加入群组 (id positional)
|
|
305
|
-
|
|
306
|
-
# Instagram (browser)
|
|
307
|
-
opencli instagram explore # 探索
|
|
308
|
-
opencli instagram profile username # 用户资料 (id positional)
|
|
309
|
-
opencli instagram search "AI" # 搜索 (query positional)
|
|
310
|
-
opencli instagram user username # 用户详情 (id positional)
|
|
311
|
-
opencli instagram followers username # 粉丝 (id positional)
|
|
312
|
-
opencli instagram following username # 关注 (id positional)
|
|
313
|
-
opencli instagram follow username # 关注用户 (id positional)
|
|
314
|
-
opencli instagram unfollow username # 取消关注 (id positional)
|
|
315
|
-
opencli instagram like postid # 点赞 (id positional)
|
|
316
|
-
opencli instagram unlike postid # 取消点赞 (id positional)
|
|
317
|
-
opencli instagram comment postid "评论" # 评论 (id + text positional)
|
|
318
|
-
opencli instagram save postid # 收藏 (id positional)
|
|
319
|
-
opencli instagram unsave postid # 取消收藏 (id positional)
|
|
320
|
-
opencli instagram saved # 已收藏列表
|
|
321
|
-
|
|
322
|
-
# TikTok (browser)
|
|
323
|
-
opencli tiktok explore # 探索
|
|
324
|
-
opencli tiktok search "AI" # 搜索 (query positional)
|
|
325
|
-
opencli tiktok profile username # 用户资料 (id positional)
|
|
326
|
-
opencli tiktok user username # 用户详情 (id positional)
|
|
327
|
-
opencli tiktok following username # 关注列表 (id positional)
|
|
328
|
-
opencli tiktok follow username # 关注 (id positional)
|
|
329
|
-
opencli tiktok unfollow username # 取消关注 (id positional)
|
|
330
|
-
opencli tiktok like videoid # 点赞 (id positional)
|
|
331
|
-
opencli tiktok unlike videoid # 取消点赞 (id positional)
|
|
332
|
-
opencli tiktok comment videoid "评论" # 评论 (id + text positional)
|
|
333
|
-
opencli tiktok save videoid # 收藏 (id positional)
|
|
334
|
-
opencli tiktok unsave videoid # 取消收藏 (id positional)
|
|
335
|
-
opencli tiktok live # 直播
|
|
336
|
-
opencli tiktok notifications # 通知
|
|
337
|
-
opencli tiktok friends # 朋友
|
|
338
|
-
|
|
339
|
-
# Medium (browser)
|
|
340
|
-
opencli medium feed --limit 10 # 动态流
|
|
341
|
-
opencli medium search "AI" # 搜索 (query positional)
|
|
342
|
-
opencli medium user username # 用户主页 (id positional)
|
|
343
|
-
|
|
344
|
-
# Substack (browser)
|
|
345
|
-
opencli substack feed --limit 10 # 订阅动态
|
|
346
|
-
opencli substack search "AI" # 搜索 (query positional)
|
|
347
|
-
opencli substack publication name # 出版物详情 (id positional)
|
|
348
|
-
|
|
349
|
-
# Sinablog 新浪博客 (browser)
|
|
350
|
-
opencli sinablog hot --limit 10 # 热门
|
|
351
|
-
opencli sinablog search "AI" # 搜索 (query positional)
|
|
352
|
-
opencli sinablog article url # 文章详情
|
|
353
|
-
opencli sinablog user username # 用户主页 (id positional)
|
|
354
|
-
|
|
355
|
-
# Lobsters (public)
|
|
356
|
-
opencli lobsters hot --limit 10 # 热门
|
|
357
|
-
opencli lobsters newest --limit 10 # 最新
|
|
358
|
-
opencli lobsters active --limit 10 # 活跃
|
|
359
|
-
opencli lobsters tag rust # 按标签筛选 (tag positional)
|
|
360
|
-
|
|
361
|
-
# Google (public)
|
|
362
|
-
opencli google news --limit 10 # 新闻
|
|
363
|
-
opencli google search "AI" # 搜索 (query positional)
|
|
364
|
-
opencli google suggest "AI" # 搜索建议 (query positional)
|
|
365
|
-
opencli google trends # 趋势
|
|
366
|
-
|
|
367
|
-
# DEV.to (public)
|
|
368
|
-
opencli devto top --limit 10 # 热门文章
|
|
369
|
-
opencli devto tag javascript --limit 10 # 按标签 (tag positional)
|
|
370
|
-
opencli devto user username # 用户文章 (username positional)
|
|
371
|
-
|
|
372
|
-
# Steam (public)
|
|
373
|
-
opencli steam top-sellers --limit 10 # 热销游戏
|
|
374
|
-
|
|
375
|
-
# Apple Podcasts (public)
|
|
376
|
-
opencli apple-podcasts top --limit 10 # 热门播客排行榜 (支持 --country us/cn/gb/jp)
|
|
377
|
-
opencli apple-podcasts search "科技" # 搜索播客 (query positional)
|
|
378
|
-
opencli apple-podcasts episodes 12345 # 播客剧集列表 (id positional, 用 search 获取 ID)
|
|
379
|
-
|
|
380
|
-
# arXiv (public)
|
|
381
|
-
opencli arxiv search "attention" # 搜索论文 (query positional)
|
|
382
|
-
opencli arxiv paper 1706.03762 # 论文详情 (id positional)
|
|
383
|
-
|
|
384
|
-
# Bloomberg (public RSS + browser)
|
|
385
|
-
opencli bloomberg main --limit 10 # Bloomberg 首页头条 (RSS)
|
|
386
|
-
opencli bloomberg markets --limit 10 # 市场新闻 (RSS)
|
|
387
|
-
opencli bloomberg tech --limit 10 # 科技新闻 (RSS)
|
|
388
|
-
opencli bloomberg politics --limit 10 # 政治新闻 (RSS)
|
|
389
|
-
opencli bloomberg economics --limit 10 # 经济新闻 (RSS)
|
|
390
|
-
opencli bloomberg opinions --limit 10 # 观点 (RSS)
|
|
391
|
-
opencli bloomberg industries --limit 10 # 行业新闻 (RSS)
|
|
392
|
-
opencli bloomberg businessweek --limit 10 # Businessweek (RSS)
|
|
393
|
-
opencli bloomberg feeds # 列出所有 RSS feed 别名
|
|
394
|
-
opencli bloomberg news "https://..." # 阅读 Bloomberg 文章全文 (link positional, browser)
|
|
395
|
-
|
|
396
|
-
# Coupang 쿠팡 (browser)
|
|
397
|
-
opencli coupang search "耳机" # 搜索商品 (query positional, 支持 --filter rocket)
|
|
398
|
-
opencli coupang add-to-cart 12345 # 加入购物车 (product-id positional, 或 --url)
|
|
399
|
-
|
|
400
|
-
# Dictionary (public)
|
|
401
|
-
opencli dictionary search "serendipity" # 单词释义 (word positional)
|
|
402
|
-
opencli dictionary synonyms "happy" # 近义词 (word positional)
|
|
403
|
-
opencli dictionary examples "ubiquitous" # 例句 (word positional)
|
|
404
|
-
|
|
405
|
-
# 豆包 Doubao Web (browser)
|
|
406
|
-
opencli doubao status # 检查豆包页面状态
|
|
407
|
-
opencli doubao new # 新建对话
|
|
408
|
-
opencli doubao send "你好" # 发送消息 (text positional)
|
|
409
|
-
opencli doubao read # 读取对话记录
|
|
410
|
-
opencli doubao ask "问题" # 一键提问并等回复 (text positional)
|
|
411
|
-
|
|
412
|
-
# 京东 JD (browser)
|
|
413
|
-
opencli jd item 100291143898 # 商品详情 (sku positional, 含价格/主图/规格)
|
|
414
|
-
|
|
415
|
-
# LinkedIn (browser)
|
|
416
|
-
opencli linkedin search "AI engineer" # 搜索职位 (query positional, 支持 --location/--company/--remote)
|
|
417
|
-
opencli linkedin timeline --limit 20 # 首页动态流
|
|
418
|
-
|
|
419
|
-
# Pixiv (browser)
|
|
420
|
-
opencli pixiv ranking --limit 20 # 插画排行榜 (支持 --mode daily/weekly/monthly)
|
|
421
|
-
opencli pixiv search "風景" # 搜索插画 (query positional)
|
|
422
|
-
opencli pixiv user 12345 # 画师资料 (uid positional)
|
|
423
|
-
opencli pixiv illusts 12345 # 画师作品列表 (user-id positional)
|
|
424
|
-
opencli pixiv detail 12345 # 插画详情 (id positional)
|
|
425
|
-
opencli pixiv download 12345 # 下载插画 (illust-id positional)
|
|
426
|
-
|
|
427
|
-
# Web (browser)
|
|
428
|
-
opencli web read --url "https://..." # 抓取任意网页并导出为 Markdown
|
|
429
|
-
|
|
430
|
-
# 微信公众号 Weixin (browser)
|
|
431
|
-
opencli weixin download --url "https://mp.weixin.qq.com/s/xxx" # 下载公众号文章为 Markdown
|
|
432
|
-
|
|
433
|
-
# 小宇宙 Xiaoyuzhou (public)
|
|
434
|
-
opencli xiaoyuzhou podcast 12345 # 播客资料 (id positional)
|
|
435
|
-
opencli xiaoyuzhou podcast-episodes 12345 # 播客剧集列表 (id positional)
|
|
436
|
-
opencli xiaoyuzhou episode 12345 # 单集详情 (id positional)
|
|
437
|
-
|
|
438
|
-
# Wikipedia (public)
|
|
439
|
-
opencli wikipedia search "AI" # 搜索 (query positional)
|
|
440
|
-
opencli wikipedia summary "Python" # 摘要 (title positional)
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
### Desktop Adapter Commands
|
|
444
|
-
|
|
445
|
-
```bash
|
|
446
|
-
# Cursor (desktop — CDP via Electron)
|
|
447
|
-
opencli cursor status # 检查连接
|
|
448
|
-
opencli cursor send "message" # 发送消息
|
|
449
|
-
opencli cursor read # 读取回复
|
|
450
|
-
opencli cursor new # 新建对话
|
|
451
|
-
opencli cursor dump # 导出 DOM 调试信息
|
|
452
|
-
opencli cursor composer # Composer 模式
|
|
453
|
-
opencli cursor model claude # 切换模型
|
|
454
|
-
opencli cursor extract-code # 提取代码块
|
|
455
|
-
opencli cursor ask "question" # 一键提问并等回复
|
|
456
|
-
opencli cursor screenshot # 截图
|
|
457
|
-
opencli cursor history # 对话历史
|
|
458
|
-
opencli cursor export # 导出对话
|
|
459
|
-
|
|
460
|
-
# Codex (desktop — headless CLI agent)
|
|
461
|
-
opencli codex status # 检查连接
|
|
462
|
-
opencli codex send "message" # 发送消息
|
|
463
|
-
opencli codex read # 读取回复
|
|
464
|
-
opencli codex new # 新建对话
|
|
465
|
-
opencli codex dump # 导出调试信息
|
|
466
|
-
opencli codex extract-diff # 提取 diff
|
|
467
|
-
opencli codex model gpt-4 # 切换模型
|
|
468
|
-
opencli codex ask "question" # 一键提问并等回复
|
|
469
|
-
opencli codex screenshot # 截图
|
|
470
|
-
opencli codex history # 对话历史
|
|
471
|
-
opencli codex export # 导出对话
|
|
472
|
-
|
|
473
|
-
# ChatGPT (desktop — macOS AppleScript/CDP)
|
|
474
|
-
opencli chatgpt status # 检查应用状态
|
|
475
|
-
opencli chatgpt new # 新建对话
|
|
476
|
-
opencli chatgpt send "message" # 发送消息
|
|
477
|
-
opencli chatgpt read # 读取回复
|
|
478
|
-
opencli chatgpt ask "question" # 一键提问并等回复
|
|
479
|
-
|
|
480
|
-
# ChatWise (desktop — multi-LLM client)
|
|
481
|
-
opencli chatwise status # 检查连接
|
|
482
|
-
opencli chatwise new # 新建对话
|
|
483
|
-
opencli chatwise send "message" # 发送消息
|
|
484
|
-
opencli chatwise read # 读取回复
|
|
485
|
-
opencli chatwise ask "question" # 一键提问并等回复
|
|
486
|
-
opencli chatwise model claude # 切换模型
|
|
487
|
-
opencli chatwise history # 对话历史
|
|
488
|
-
opencli chatwise export # 导出对话
|
|
489
|
-
opencli chatwise screenshot # 截图
|
|
490
|
-
|
|
491
|
-
# Notion (desktop — CDP via Electron)
|
|
492
|
-
opencli notion status # 检查连接
|
|
493
|
-
opencli notion search "keyword" # 搜索页面
|
|
494
|
-
opencli notion read # 读取当前页面
|
|
495
|
-
opencli notion new # 新建页面
|
|
496
|
-
opencli notion write "content" # 写入内容
|
|
497
|
-
opencli notion sidebar # 侧边栏导航
|
|
498
|
-
opencli notion favorites # 收藏列表
|
|
499
|
-
opencli notion export # 导出
|
|
500
|
-
|
|
501
|
-
# Discord App (desktop — CDP via Electron)
|
|
502
|
-
opencli discord-app status # 检查连接
|
|
503
|
-
opencli discord-app send "message" # 发送消息
|
|
504
|
-
opencli discord-app read # 读取消息
|
|
505
|
-
opencli discord-app channels # 频道列表
|
|
506
|
-
opencli discord-app servers # 服务器列表
|
|
507
|
-
opencli discord-app search "keyword" # 搜索
|
|
508
|
-
opencli discord-app members # 成员列表
|
|
509
|
-
|
|
510
|
-
# Doubao App 豆包桌面版 (desktop — CDP via Electron)
|
|
511
|
-
opencli doubao-app status # 检查连接
|
|
512
|
-
opencli doubao-app new # 新建对话
|
|
513
|
-
opencli doubao-app send "message" # 发送消息
|
|
514
|
-
opencli doubao-app read # 读取回复
|
|
515
|
-
opencli doubao-app ask "question" # 一键提问并等回复
|
|
516
|
-
opencli doubao-app screenshot # 截图
|
|
517
|
-
opencli doubao-app dump # 导出 DOM 调试信息
|
|
518
|
-
```
|
|
519
|
-
|
|
520
|
-
### Management Commands
|
|
521
|
-
|
|
522
|
-
```bash
|
|
523
|
-
opencli list # List all commands (including External CLIs)
|
|
524
|
-
opencli list --json # JSON output
|
|
525
|
-
opencli list -f yaml # YAML output
|
|
526
|
-
opencli install <name> # Auto-install an external CLI (e.g., gh, obsidian)
|
|
527
|
-
opencli register <name> # Register a local custom CLI for unified discovery
|
|
528
|
-
opencli validate # Validate all CLI definitions
|
|
529
|
-
opencli validate bilibili # Validate specific site
|
|
530
|
-
opencli doctor # Diagnose browser bridge (auto-starts daemon, includes live test)
|
|
531
|
-
```
|
|
532
|
-
|
|
533
|
-
### AI Agent Workflow
|
|
534
|
-
|
|
535
|
-
```bash
|
|
536
|
-
# Deep Explore: network intercept → response analysis → capability inference
|
|
537
|
-
opencli explore <url> --site <name>
|
|
538
|
-
|
|
539
|
-
# Synthesize: generate evaluate-based YAML pipelines from explore artifacts
|
|
540
|
-
opencli synthesize <site>
|
|
541
|
-
|
|
542
|
-
# Generate: one-shot explore → synthesize → register
|
|
543
|
-
opencli generate <url> --goal "hot"
|
|
544
|
-
|
|
545
|
-
# Record: YOU operate the page, opencli captures every API call → YAML candidates
|
|
546
|
-
# Opens the URL in automation window, injects fetch/XHR interceptor into ALL tabs,
|
|
547
|
-
# polls every 2s, auto-stops after 60s (or press Enter to stop early).
|
|
548
|
-
opencli record <url> # 录制,site name 从域名推断
|
|
549
|
-
opencli record <url> --site mysite # 指定 site name
|
|
550
|
-
opencli record <url> --timeout 120000 # 自定义超时(毫秒,默认 60000)
|
|
551
|
-
opencli record <url> --poll 1000 # 缩短轮询间隔(毫秒,默认 2000)
|
|
552
|
-
opencli record <url> --out .opencli/record/x # 自定义输出目录
|
|
553
|
-
# Output:
|
|
554
|
-
# .opencli/record/<site>/captured.json ← 原始捕获数据(带 url/method/body)
|
|
555
|
-
# .opencli/record/<site>/candidates/*.yaml ← 高置信度候选适配器(score ≥ 8,有 array 结果)
|
|
556
|
-
|
|
557
|
-
# Strategy Cascade: auto-probe PUBLIC → COOKIE → HEADER
|
|
558
|
-
opencli cascade <api-url>
|
|
559
|
-
|
|
560
|
-
# Explore with interactive fuzzing (click buttons to trigger lazy APIs)
|
|
561
|
-
opencli explore <url> --auto --click "字幕,CC,评论"
|
|
562
|
-
|
|
563
|
-
# Validate: validate adapter definitions
|
|
564
|
-
opencli validate
|
|
565
|
-
```
|
|
566
|
-
|
|
567
|
-
## Output Formats
|
|
568
|
-
|
|
569
|
-
All built-in commands support `--format` / `-f` with `table`, `json`, `yaml`, `md`, and `csv`.
|
|
570
|
-
The `list` command supports the same formats and also keeps `--json` as a compatibility alias.
|
|
571
|
-
|
|
572
|
-
```bash
|
|
573
|
-
opencli list -f yaml # YAML command registry
|
|
574
|
-
opencli bilibili hot -f table # Default: rich table
|
|
575
|
-
opencli bilibili hot -f json # JSON (pipe to jq, feed to AI agent)
|
|
576
|
-
opencli bilibili hot -f yaml # YAML (readable structured output)
|
|
577
|
-
opencli bilibili hot -f md # Markdown
|
|
578
|
-
opencli bilibili hot -f csv # CSV
|
|
579
|
-
```
|
|
580
|
-
|
|
581
|
-
## Verbose Mode
|
|
582
|
-
|
|
583
|
-
```bash
|
|
584
|
-
opencli bilibili hot -v # Show each pipeline step and data flow
|
|
585
|
-
```
|
|
586
|
-
|
|
587
|
-
## Record Workflow
|
|
588
|
-
|
|
589
|
-
`record` 是为「无法用 `explore` 自动发现」的页面(需要登录操作、复杂交互、SPA 内路由)准备的手动录制方案。
|
|
590
|
-
|
|
591
|
-
### 工作原理
|
|
592
|
-
|
|
593
|
-
```
|
|
594
|
-
opencli record <url>
|
|
595
|
-
→ 打开 automation window 并导航到目标 URL
|
|
596
|
-
→ 向所有 tab 注入 fetch/XHR 拦截器(幂等,可重复注入)
|
|
597
|
-
→ 每 2s 轮询一次:发现新 tab 自动注入,drain 所有 tab 的捕获缓冲区
|
|
598
|
-
→ 超时(默认 60s)或按 Enter 停止
|
|
599
|
-
→ 分析捕获到的 JSON 请求:去重 → 评分 → 生成候选 YAML
|
|
600
|
-
```
|
|
601
|
-
|
|
602
|
-
**拦截器特性**:
|
|
603
|
-
- 同时 patch `window.fetch` 和 `XMLHttpRequest`
|
|
604
|
-
- 只捕获 `Content-Type: application/json` 的响应
|
|
605
|
-
- 过滤纯对象少于 2 个 key 的响应(避免 tracking/ping)
|
|
606
|
-
- 跨 tab 隔离:每个 tab 独立缓冲区,轮询时分别 drain
|
|
607
|
-
- 幂等注入:同一 tab 二次注入时先 restore 原始函数再重新 patch,不丢失已捕获数据
|
|
608
|
-
|
|
609
|
-
### 使用步骤
|
|
610
|
-
|
|
611
|
-
```bash
|
|
612
|
-
# 1. 启动录制(建议 --timeout 给足操作时间)
|
|
613
|
-
opencli record "https://example.com/page" --timeout 120000
|
|
614
|
-
|
|
615
|
-
# 2. 在弹出的 automation window 里正常操作页面:
|
|
616
|
-
# - 打开列表、搜索、点击条目、切换 Tab
|
|
617
|
-
# - 凡是触发网络请求的操作都会被捕获
|
|
618
|
-
|
|
619
|
-
# 3. 完成操作后按 Enter 停止(或等超时自动停止)
|
|
620
|
-
|
|
621
|
-
# 4. 查看结果
|
|
622
|
-
cat .opencli/record/<site>/captured.json # 原始捕获
|
|
623
|
-
ls .opencli/record/<site>/candidates/ # 候选 YAML
|
|
624
|
-
```
|
|
625
|
-
|
|
626
|
-
### 页面类型与捕获预期
|
|
627
|
-
|
|
628
|
-
| 页面类型 | 预期捕获量 | 说明 |
|
|
629
|
-
|---------|-----------|------|
|
|
630
|
-
| 列表/搜索页 | 多(5~20+) | 每次搜索/翻页都会触发新请求 |
|
|
631
|
-
| 详情页(只读) | 少(1~5) | 首屏数据一次性返回,后续操作走 form/redirect |
|
|
632
|
-
| SPA 内路由跳转 | 中等 | 路由切换会触发新接口,但首屏请求在注入前已发出 |
|
|
633
|
-
| 需要登录的页面 | 视操作而定 | 确保 Chrome 已登录目标网站 |
|
|
634
|
-
|
|
635
|
-
> **注意**:如果页面在导航完成前就发出了大部分请求(服务端渲染 / SSR 注水),拦截器会错过这些请求。
|
|
636
|
-
> 解决方案:在页面加载完成后,手动触发能产生新请求的操作(搜索、翻页、切 Tab、展开折叠项等)。
|
|
637
|
-
|
|
638
|
-
### 候选 YAML → TS CLI 转换
|
|
639
|
-
|
|
640
|
-
生成的候选 YAML 是起点,通常需要转换为 TypeScript(尤其是 tae 等内部系统):
|
|
641
|
-
|
|
642
|
-
**候选 YAML 结构**(自动生成):
|
|
643
|
-
```yaml
|
|
644
|
-
site: tae
|
|
645
|
-
name: getList # 从 URL path 推断的名称
|
|
646
|
-
strategy: cookie
|
|
647
|
-
browser: true
|
|
648
|
-
pipeline:
|
|
649
|
-
- navigate: https://...
|
|
650
|
-
- evaluate: |
|
|
651
|
-
(async () => {
|
|
652
|
-
const res = await fetch('/approval/getList.json?procInsId=...', { credentials: 'include' });
|
|
653
|
-
const data = await res.json();
|
|
654
|
-
return (data?.content?.operatorRecords || []).map(item => ({ ... }));
|
|
655
|
-
})()
|
|
656
|
-
```
|
|
657
|
-
|
|
658
|
-
**转换为 TS CLI**(参考 `src/clis/tae/add-expense.ts` 风格):
|
|
659
|
-
```typescript
|
|
660
|
-
import { cli, Strategy } from '../../registry.js';
|
|
661
|
-
|
|
662
|
-
cli({
|
|
663
|
-
site: 'tae',
|
|
664
|
-
name: 'get-approval',
|
|
665
|
-
description: '查看报销单审批流程和操作记录',
|
|
666
|
-
domain: 'tae.alibaba-inc.com',
|
|
667
|
-
strategy: Strategy.COOKIE,
|
|
668
|
-
browser: true,
|
|
669
|
-
args: [
|
|
670
|
-
{ name: 'proc_ins_id', type: 'string', required: true, positional: true, help: '流程实例 ID(procInsId)' },
|
|
671
|
-
],
|
|
672
|
-
columns: ['step', 'operator', 'action', 'time'],
|
|
673
|
-
func: async (page, kwargs) => {
|
|
674
|
-
await page.goto('https://tae.alibaba-inc.com/expense/pc.html?_authType=SAML');
|
|
675
|
-
await page.wait(2);
|
|
676
|
-
const result = await page.evaluate(`(async () => {
|
|
677
|
-
const res = await fetch('/approval/getList.json?taskId=&procInsId=${kwargs.proc_ins_id}', {
|
|
678
|
-
credentials: 'include'
|
|
679
|
-
});
|
|
680
|
-
const data = await res.json();
|
|
681
|
-
return data?.content?.operatorRecords || [];
|
|
682
|
-
})()`);
|
|
683
|
-
return (result as any[]).map((r, i) => ({
|
|
684
|
-
step: i + 1,
|
|
685
|
-
operator: r.operatorName || r.userId,
|
|
686
|
-
action: r.operationType,
|
|
687
|
-
time: r.operateTime,
|
|
688
|
-
}));
|
|
689
|
-
},
|
|
690
|
-
});
|
|
691
|
-
```
|
|
692
|
-
|
|
693
|
-
**转换要点**:
|
|
694
|
-
1. URL 中的动态 ID(`procInsId`、`taskId` 等)提取为 `args`
|
|
695
|
-
2. `captured.json` 里的真实 body 结构用于确定正确的数据路径(如 `content.operatorRecords`)
|
|
696
|
-
3. tae 系统统一用 `{ success, content, errorCode, errorMsg }` 外层包裹,取数据要走 `content.*`
|
|
697
|
-
4. 认证方式:cookie(`credentials: 'include'`),不需要额外 header
|
|
698
|
-
5. 文件放入 `src/clis/<site>/`,无需手动注册,`npm run build` 后自动发现
|
|
699
|
-
|
|
700
|
-
### 故障排查
|
|
701
|
-
|
|
702
|
-
| 现象 | 原因 | 解法 |
|
|
703
|
-
|------|------|------|
|
|
704
|
-
| 捕获 0 条请求 | 拦截器注入失败,或页面无 JSON API | 检查 daemon 是否运行:`curl localhost:19825/status` |
|
|
705
|
-
| 捕获量少(1~3 条) | 页面是只读详情页,首屏数据已在注入前发出 | 手动操作触发更多请求(搜索/翻页),或换用列表页 |
|
|
706
|
-
| 候选 YAML 为 0 | 捕获到的 JSON 都没有 array 结构 | 直接看 `captured.json` 手写 TS CLI |
|
|
707
|
-
| 新开的 tab 没有被拦截 | 轮询间隔内 tab 已关闭 | 缩短 `--poll 500` |
|
|
708
|
-
| 二次运行 record 时数据不连续 | 正常,每次 `record` 启动都是新的 automation window | 无需处理 |
|
|
709
|
-
|
|
710
|
-
## Creating Adapters
|
|
711
|
-
|
|
712
|
-
> [!TIP]
|
|
713
|
-
> **快速模式**:如果你只想为一个具体页面生成一个命令,直接看 [CLI-ONESHOT.md](./CLI-ONESHOT.md)。
|
|
714
|
-
> 只需要一个 URL + 一句话描述,4 步搞定。
|
|
715
|
-
|
|
716
|
-
> [!IMPORTANT]
|
|
717
|
-
> **完整模式 — 在写任何代码之前,先阅读 [CLI-EXPLORER.md](./CLI-EXPLORER.md)。**
|
|
718
|
-
> 它包含:① AI Agent 浏览器探索工作流 ② 认证策略决策树 ③ 平台 SDK(如 Bilibili 的 `apiGet`/`fetchJson`)④ YAML vs TS 选择指南 ⑤ `tap` 步骤调试方法 ⑥ 级联请求模板 ⑦ 常见陷阱表。
|
|
719
|
-
> **下方仅为简化模板参考,直接使用极易踩坑。**
|
|
720
|
-
|
|
721
|
-
### YAML Pipeline (declarative, recommended)
|
|
722
|
-
|
|
723
|
-
Create `src/clis/<site>/<name>.yaml`:
|
|
724
|
-
|
|
725
|
-
```yaml
|
|
726
|
-
site: mysite
|
|
727
|
-
name: hot
|
|
728
|
-
description: Hot topics
|
|
729
|
-
domain: www.mysite.com
|
|
730
|
-
strategy: cookie # public | cookie | header | intercept | ui
|
|
731
|
-
browser: true
|
|
732
|
-
|
|
733
|
-
args:
|
|
734
|
-
limit:
|
|
735
|
-
type: int
|
|
736
|
-
default: 20
|
|
737
|
-
description: Number of items
|
|
738
|
-
|
|
739
|
-
pipeline:
|
|
740
|
-
- navigate: https://www.mysite.com
|
|
741
|
-
|
|
742
|
-
- evaluate: |
|
|
743
|
-
(async () => {
|
|
744
|
-
const res = await fetch('/api/hot', { credentials: 'include' });
|
|
745
|
-
const d = await res.json();
|
|
746
|
-
return d.data.items.map(item => ({
|
|
747
|
-
title: item.title,
|
|
748
|
-
score: item.score,
|
|
749
|
-
}));
|
|
750
|
-
})()
|
|
751
|
-
|
|
752
|
-
- map:
|
|
753
|
-
rank: ${{ index + 1 }}
|
|
754
|
-
title: ${{ item.title }}
|
|
755
|
-
score: ${{ item.score }}
|
|
756
|
-
|
|
757
|
-
- limit: ${{ args.limit }}
|
|
758
|
-
|
|
759
|
-
columns: [rank, title, score]
|
|
760
|
-
```
|
|
761
|
-
|
|
762
|
-
For public APIs (no browser):
|
|
763
|
-
|
|
764
|
-
```yaml
|
|
765
|
-
strategy: public
|
|
766
|
-
browser: false
|
|
767
|
-
|
|
768
|
-
pipeline:
|
|
769
|
-
- fetch:
|
|
770
|
-
url: https://api.example.com/hot.json
|
|
771
|
-
- select: data.items
|
|
772
|
-
- map:
|
|
773
|
-
title: ${{ item.title }}
|
|
774
|
-
- limit: ${{ args.limit }}
|
|
775
|
-
```
|
|
776
|
-
|
|
777
|
-
### TypeScript Adapter (programmatic)
|
|
778
|
-
|
|
779
|
-
Create `src/clis/<site>/<name>.ts`. It will be automatically dynamically loaded (DO NOT manually import it in `index.ts`):
|
|
780
|
-
|
|
781
|
-
```typescript
|
|
782
|
-
import { cli, Strategy } from '../../registry.js';
|
|
783
|
-
|
|
784
|
-
cli({
|
|
785
|
-
site: 'mysite',
|
|
786
|
-
name: 'search',
|
|
787
|
-
strategy: Strategy.INTERCEPT, // Or COOKIE
|
|
788
|
-
args: [{ name: 'query', required: true, positional: true }],
|
|
789
|
-
columns: ['rank', 'title', 'url'],
|
|
790
|
-
func: async (page, kwargs) => {
|
|
791
|
-
await page.goto('https://www.mysite.com/search');
|
|
792
|
-
|
|
793
|
-
// Inject native XHR/Fetch interceptor hook
|
|
794
|
-
await page.installInterceptor('/api/search');
|
|
795
|
-
|
|
796
|
-
// Auto scroll down to trigger lazy loading
|
|
797
|
-
await page.autoScroll({ times: 3, delayMs: 2000 });
|
|
798
|
-
|
|
799
|
-
// Retrieve intercepted JSON payloads
|
|
800
|
-
const requests = await page.getInterceptedRequests();
|
|
801
|
-
|
|
802
|
-
let results = [];
|
|
803
|
-
for (const req of requests) {
|
|
804
|
-
results.push(...req.data.items);
|
|
805
|
-
}
|
|
806
|
-
return results.map((item, i) => ({
|
|
807
|
-
rank: i + 1, title: item.title, url: item.url,
|
|
808
|
-
}));
|
|
809
|
-
},
|
|
810
|
-
});
|
|
811
|
-
```
|
|
812
|
-
|
|
813
|
-
**When to use TS**: XHR interception (`page.installInterceptor`), infinite scrolling (`page.autoScroll`), cookie extraction, complex data transforms (like GraphQL unwrapping).
|
|
814
|
-
|
|
815
|
-
## Pipeline Steps
|
|
816
|
-
|
|
817
|
-
| Step | Description | Example |
|
|
818
|
-
|------|-------------|---------|
|
|
819
|
-
| `navigate` | Go to URL | `navigate: https://example.com` |
|
|
820
|
-
| `fetch` | HTTP request (browser cookies) | `fetch: { url: "...", params: { q: "..." } }` |
|
|
821
|
-
| `evaluate` | Run JavaScript in page | `evaluate: \| (async () => { ... })()` |
|
|
822
|
-
| `select` | Extract JSON path | `select: data.items` |
|
|
823
|
-
| `map` | Map fields | `map: { title: "${{ item.title }}" }` |
|
|
824
|
-
| `filter` | Filter items | `filter: item.score > 100` |
|
|
825
|
-
| `sort` | Sort items | `sort: { by: score, order: desc }` |
|
|
826
|
-
| `limit` | Cap result count | `limit: ${{ args.limit }}` |
|
|
827
|
-
| `intercept` | Declarative XHR capture | `intercept: { trigger: "navigate:...", capture: "api/hot" }` |
|
|
828
|
-
| `tap` | Store action + XHR capture | `tap: { store: "feed", action: "fetchFeeds", capture: "homefeed" }` |
|
|
829
|
-
| `snapshot` | Page accessibility tree | `snapshot: { interactive: true }` |
|
|
830
|
-
| `click` | Click element | `click: ${{ ref }}` |
|
|
831
|
-
| `type` | Type text | `type: { ref: "@1", text: "hello" }` |
|
|
832
|
-
| `wait` | Wait for time/text | `wait: 2` or `wait: { text: "loaded" }` |
|
|
833
|
-
| `press` | Press key | `press: Enter` |
|
|
834
|
-
|
|
835
|
-
## Template Syntax
|
|
836
|
-
|
|
837
|
-
```yaml
|
|
838
|
-
# Arguments with defaults
|
|
839
|
-
${{ args.query }}
|
|
840
|
-
${{ args.limit | default(20) }}
|
|
841
|
-
|
|
842
|
-
# Current item (in map/filter)
|
|
843
|
-
${{ item.title }}
|
|
844
|
-
${{ item.data.nested.field }}
|
|
845
|
-
|
|
846
|
-
# Index (0-based)
|
|
847
|
-
${{ index }}
|
|
848
|
-
${{ index + 1 }}
|
|
849
|
-
```
|
|
850
|
-
|
|
851
|
-
## 5-Tier Authentication Strategy
|
|
852
|
-
|
|
853
|
-
| Tier | Name | Method | Example |
|
|
854
|
-
|------|------|--------|---------|
|
|
855
|
-
| 1 | `public` | No auth, Node.js fetch | Hacker News, V2EX |
|
|
856
|
-
| 2 | `cookie` | Browser fetch with `credentials: include` | Bilibili, Zhihu |
|
|
857
|
-
| 3 | `header` | Custom headers (ct0, Bearer) | Twitter GraphQL |
|
|
858
|
-
| 4 | `intercept` | XHR interception + store mutation | 小红书 Pinia |
|
|
859
|
-
| 5 | `ui` | Full UI automation (click/type/scroll) | Last resort |
|
|
860
|
-
|
|
861
|
-
## Environment Variables
|
|
862
|
-
|
|
863
|
-
| Variable | Default | Description |
|
|
864
|
-
|----------|---------|-------------|
|
|
865
|
-
| `OPENCLI_DAEMON_PORT` | 19825 | Daemon listen port |
|
|
866
|
-
| `OPENCLI_BROWSER_CONNECT_TIMEOUT` | 30 | Browser connection timeout (sec) |
|
|
867
|
-
| `OPENCLI_BROWSER_COMMAND_TIMEOUT` | 45 | Command execution timeout (sec) |
|
|
868
|
-
| `OPENCLI_BROWSER_EXPLORE_TIMEOUT` | 120 | Explore timeout (sec) |
|
|
869
|
-
| `OPENCLI_VERBOSE` | — | Show daemon/extension logs |
|
|
870
|
-
|
|
871
|
-
## Troubleshooting
|
|
872
|
-
|
|
873
|
-
| Issue | Solution |
|
|
874
|
-
|-------|----------|
|
|
875
|
-
| `npx not found` | Install Node.js: `brew install node` |
|
|
876
|
-
| `Extension not connected` | 1) Chrome must be open 2) Install opencli Browser Bridge extension |
|
|
877
|
-
| `Target page context` error | Add `navigate:` step before `evaluate:` in YAML |
|
|
878
|
-
| Empty table data | Check if evaluate returns correct data path |
|
|
879
|
-
| Daemon issues | `curl localhost:19825/status` to check, `curl localhost:19825/logs` for extension logs |
|