@jackwener/opencli 1.3.0 → 1.3.2

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.
Files changed (218) hide show
  1. package/CHANGELOG.md +128 -0
  2. package/README.md +44 -5
  3. package/README.zh-CN.md +44 -5
  4. package/SKILL.md +317 -5
  5. package/TESTING.md +4 -4
  6. package/dist/browser/errors.d.ts +2 -1
  7. package/dist/browser/errors.js +9 -10
  8. package/dist/build-manifest.js +1 -3
  9. package/dist/cli-manifest.json +2573 -989
  10. package/dist/cli.js +42 -2
  11. package/dist/clis/bilibili/download.js +20 -65
  12. package/dist/clis/bilibili/utils.js +2 -1
  13. package/dist/clis/chaoxing/assignments.js +2 -1
  14. package/dist/clis/doubao/ask.d.ts +1 -0
  15. package/dist/clis/doubao/ask.js +35 -0
  16. package/dist/clis/doubao/common.d.ts +23 -0
  17. package/dist/clis/doubao/common.js +564 -0
  18. package/dist/clis/doubao/new.d.ts +1 -0
  19. package/dist/clis/doubao/new.js +20 -0
  20. package/dist/clis/doubao/read.d.ts +1 -0
  21. package/dist/clis/doubao/read.js +19 -0
  22. package/dist/clis/doubao/send.d.ts +1 -0
  23. package/dist/clis/doubao/send.js +22 -0
  24. package/dist/clis/doubao/status.d.ts +1 -0
  25. package/dist/clis/doubao/status.js +24 -0
  26. package/dist/clis/doubao-app/ask.d.ts +1 -0
  27. package/dist/clis/doubao-app/ask.js +53 -0
  28. package/dist/clis/doubao-app/common.d.ts +37 -0
  29. package/dist/clis/doubao-app/common.js +110 -0
  30. package/dist/clis/doubao-app/dump.d.ts +1 -0
  31. package/dist/clis/doubao-app/dump.js +24 -0
  32. package/dist/clis/doubao-app/new.d.ts +1 -0
  33. package/dist/clis/doubao-app/new.js +20 -0
  34. package/dist/clis/doubao-app/read.d.ts +1 -0
  35. package/dist/clis/doubao-app/read.js +18 -0
  36. package/dist/clis/doubao-app/screenshot.d.ts +1 -0
  37. package/dist/clis/doubao-app/screenshot.js +18 -0
  38. package/dist/clis/doubao-app/send.d.ts +1 -0
  39. package/dist/clis/doubao-app/send.js +27 -0
  40. package/dist/clis/doubao-app/status.d.ts +1 -0
  41. package/dist/clis/doubao-app/status.js +16 -0
  42. package/dist/clis/hackernews/ask.yaml +38 -0
  43. package/dist/clis/hackernews/best.yaml +38 -0
  44. package/dist/clis/hackernews/jobs.yaml +36 -0
  45. package/dist/clis/hackernews/new.yaml +38 -0
  46. package/dist/clis/hackernews/search.yaml +44 -0
  47. package/dist/clis/hackernews/show.yaml +38 -0
  48. package/dist/clis/hackernews/top.yaml +3 -1
  49. package/dist/clis/hackernews/user.yaml +25 -0
  50. package/dist/clis/twitter/download.js +13 -97
  51. package/dist/clis/twitter/thread.js +2 -1
  52. package/dist/clis/v2ex/member.yaml +29 -0
  53. package/dist/clis/v2ex/node.yaml +34 -0
  54. package/dist/clis/v2ex/nodes.yaml +31 -0
  55. package/dist/clis/v2ex/replies.yaml +32 -0
  56. package/dist/clis/v2ex/user.yaml +34 -0
  57. package/dist/clis/weibo/search.d.ts +1 -0
  58. package/dist/clis/weibo/search.js +73 -0
  59. package/dist/clis/weixin/download.d.ts +12 -0
  60. package/dist/clis/weixin/download.js +183 -0
  61. package/dist/clis/xiaohongshu/download.js +12 -60
  62. package/dist/clis/xiaohongshu/publish.d.ts +18 -0
  63. package/dist/clis/xiaohongshu/publish.js +352 -0
  64. package/dist/clis/xiaohongshu/search.js +47 -15
  65. package/dist/clis/xiaohongshu/search.test.d.ts +1 -0
  66. package/dist/clis/xiaohongshu/search.test.js +114 -0
  67. package/dist/clis/yollomi/background.d.ts +4 -0
  68. package/dist/clis/yollomi/background.js +45 -0
  69. package/dist/clis/yollomi/edit.d.ts +5 -0
  70. package/dist/clis/yollomi/edit.js +56 -0
  71. package/dist/clis/yollomi/face-swap.d.ts +5 -0
  72. package/dist/clis/yollomi/face-swap.js +43 -0
  73. package/dist/clis/yollomi/generate.d.ts +9 -0
  74. package/dist/clis/yollomi/generate.js +100 -0
  75. package/dist/clis/yollomi/models.d.ts +1 -0
  76. package/dist/clis/yollomi/models.js +33 -0
  77. package/dist/clis/yollomi/object-remover.d.ts +4 -0
  78. package/dist/clis/yollomi/object-remover.js +42 -0
  79. package/dist/clis/yollomi/remove-bg.d.ts +4 -0
  80. package/dist/clis/yollomi/remove-bg.js +38 -0
  81. package/dist/clis/yollomi/restore.d.ts +4 -0
  82. package/dist/clis/yollomi/restore.js +38 -0
  83. package/dist/clis/yollomi/try-on.d.ts +4 -0
  84. package/dist/clis/yollomi/try-on.js +46 -0
  85. package/dist/clis/yollomi/upload.d.ts +7 -0
  86. package/dist/clis/yollomi/upload.js +71 -0
  87. package/dist/clis/yollomi/upscale.d.ts +4 -0
  88. package/dist/clis/yollomi/upscale.js +53 -0
  89. package/dist/clis/yollomi/utils.d.ts +45 -0
  90. package/dist/clis/yollomi/utils.js +180 -0
  91. package/dist/clis/yollomi/video.d.ts +5 -0
  92. package/dist/clis/yollomi/video.js +56 -0
  93. package/dist/clis/zhihu/download.d.ts +1 -5
  94. package/dist/clis/zhihu/download.js +20 -126
  95. package/dist/clis/zhihu/download.test.js +7 -5
  96. package/dist/clis/zhihu/question.js +2 -1
  97. package/dist/commanderAdapter.js +4 -6
  98. package/dist/daemon.js +5 -2
  99. package/dist/discovery.js +10 -10
  100. package/dist/download/article-download.d.ts +59 -0
  101. package/dist/download/article-download.js +178 -0
  102. package/dist/download/media-download.d.ts +49 -0
  103. package/dist/download/media-download.js +112 -0
  104. package/dist/errors.d.ts +23 -2
  105. package/dist/errors.js +58 -2
  106. package/dist/errors.test.d.ts +1 -0
  107. package/dist/errors.test.js +59 -0
  108. package/dist/execution.js +9 -10
  109. package/dist/explore.js +4 -2
  110. package/dist/external.d.ts +15 -0
  111. package/dist/external.js +48 -2
  112. package/dist/external.test.d.ts +1 -0
  113. package/dist/external.test.js +64 -0
  114. package/dist/main.js +10 -0
  115. package/dist/plugin.d.ts +4 -0
  116. package/dist/plugin.js +45 -23
  117. package/dist/plugin.test.js +6 -1
  118. package/dist/record.d.ts +47 -0
  119. package/dist/record.js +545 -0
  120. package/dist/registry.d.ts +7 -2
  121. package/dist/registry.js +2 -6
  122. package/dist/runtime.d.ts +3 -1
  123. package/dist/runtime.js +10 -3
  124. package/dist/validate.js +1 -3
  125. package/docs/.vitepress/config.mts +1 -0
  126. package/docs/adapters/browser/doubao.md +35 -0
  127. package/docs/adapters/browser/hackernews.md +20 -4
  128. package/docs/adapters/browser/tiktok.md +1 -1
  129. package/docs/adapters/browser/v2ex.md +31 -10
  130. package/docs/adapters/browser/weibo.md +4 -0
  131. package/docs/adapters/browser/weixin.md +33 -0
  132. package/docs/adapters/browser/xiaohongshu.md +8 -6
  133. package/docs/adapters/browser/yollomi.md +69 -0
  134. package/docs/adapters/desktop/doubao-app.md +35 -0
  135. package/docs/adapters/index.md +16 -5
  136. package/docs/advanced/download.md +4 -0
  137. package/package.json +3 -1
  138. package/src/browser/errors.ts +17 -11
  139. package/src/build-manifest.ts +2 -3
  140. package/src/cli.ts +45 -2
  141. package/src/clis/bilibili/download.ts +25 -83
  142. package/src/clis/bilibili/utils.ts +2 -1
  143. package/src/clis/chaoxing/assignments.ts +2 -1
  144. package/src/clis/doubao/ask.ts +40 -0
  145. package/src/clis/doubao/common.ts +619 -0
  146. package/src/clis/doubao/new.ts +22 -0
  147. package/src/clis/doubao/read.ts +20 -0
  148. package/src/clis/doubao/send.ts +25 -0
  149. package/src/clis/doubao/status.ts +27 -0
  150. package/src/clis/doubao-app/ask.ts +60 -0
  151. package/src/clis/doubao-app/common.ts +116 -0
  152. package/src/clis/doubao-app/dump.ts +28 -0
  153. package/src/clis/doubao-app/new.ts +21 -0
  154. package/src/clis/doubao-app/read.ts +21 -0
  155. package/src/clis/doubao-app/screenshot.ts +19 -0
  156. package/src/clis/doubao-app/send.ts +30 -0
  157. package/src/clis/doubao-app/status.ts +17 -0
  158. package/src/clis/hackernews/ask.yaml +38 -0
  159. package/src/clis/hackernews/best.yaml +38 -0
  160. package/src/clis/hackernews/jobs.yaml +36 -0
  161. package/src/clis/hackernews/new.yaml +38 -0
  162. package/src/clis/hackernews/search.yaml +44 -0
  163. package/src/clis/hackernews/show.yaml +38 -0
  164. package/src/clis/hackernews/top.yaml +3 -1
  165. package/src/clis/hackernews/user.yaml +25 -0
  166. package/src/clis/twitter/download.ts +13 -111
  167. package/src/clis/twitter/thread.ts +2 -1
  168. package/src/clis/v2ex/member.yaml +29 -0
  169. package/src/clis/v2ex/node.yaml +34 -0
  170. package/src/clis/v2ex/nodes.yaml +31 -0
  171. package/src/clis/v2ex/replies.yaml +32 -0
  172. package/src/clis/v2ex/user.yaml +34 -0
  173. package/src/clis/weibo/search.ts +78 -0
  174. package/src/clis/weixin/download.ts +199 -0
  175. package/src/clis/xiaohongshu/download.ts +12 -71
  176. package/src/clis/xiaohongshu/publish.ts +392 -0
  177. package/src/clis/xiaohongshu/search.test.ts +134 -0
  178. package/src/clis/xiaohongshu/search.ts +49 -15
  179. package/src/clis/yollomi/background.ts +48 -0
  180. package/src/clis/yollomi/edit.ts +58 -0
  181. package/src/clis/yollomi/face-swap.ts +45 -0
  182. package/src/clis/yollomi/generate.ts +95 -0
  183. package/src/clis/yollomi/models.ts +38 -0
  184. package/src/clis/yollomi/object-remover.ts +44 -0
  185. package/src/clis/yollomi/remove-bg.ts +40 -0
  186. package/src/clis/yollomi/restore.ts +40 -0
  187. package/src/clis/yollomi/try-on.ts +48 -0
  188. package/src/clis/yollomi/upload.ts +78 -0
  189. package/src/clis/yollomi/upscale.ts +49 -0
  190. package/src/clis/yollomi/utils.ts +202 -0
  191. package/src/clis/yollomi/video.ts +61 -0
  192. package/src/clis/zhihu/download.test.ts +7 -5
  193. package/src/clis/zhihu/download.ts +23 -158
  194. package/src/clis/zhihu/question.ts +2 -1
  195. package/src/commanderAdapter.ts +4 -7
  196. package/src/daemon.ts +5 -2
  197. package/src/discovery.ts +26 -26
  198. package/src/download/article-download.ts +272 -0
  199. package/src/download/media-download.ts +178 -0
  200. package/src/errors.test.ts +79 -0
  201. package/src/errors.ts +92 -2
  202. package/src/execution.ts +14 -10
  203. package/src/explore.ts +4 -2
  204. package/src/external.test.ts +88 -0
  205. package/src/external.ts +56 -2
  206. package/src/generate.ts +2 -1
  207. package/src/main.ts +10 -0
  208. package/src/plugin.test.ts +7 -1
  209. package/src/plugin.ts +49 -25
  210. package/src/record.ts +617 -0
  211. package/src/registry.ts +9 -5
  212. package/src/runtime.ts +16 -4
  213. package/src/validate.ts +2 -3
  214. package/tests/e2e/browser-auth.test.ts +10 -1
  215. package/tests/e2e/browser-public.test.ts +13 -8
  216. package/tests/e2e/public-commands.test.ts +209 -21
  217. package/tests/smoke/api-health.test.ts +65 -6
  218. package/.github/workflows/release-please.yml +0 -25
@@ -0,0 +1,35 @@
1
+ # doubao
2
+
3
+ Browser adapter for [Doubao Chat](https://www.doubao.com/chat).
4
+
5
+ ## Commands
6
+
7
+ | Command | Description |
8
+ |---------|-------------|
9
+ | `opencli doubao status` | Check whether the page is reachable and whether Doubao appears logged in |
10
+ | `opencli doubao new` | Start a new Doubao conversation |
11
+ | `opencli doubao send "..."` | Send a message to the current Doubao chat |
12
+ | `opencli doubao read` | Read the visible Doubao conversation |
13
+ | `opencli doubao ask "..."` | Send a prompt and wait for a reply |
14
+
15
+ ## Prerequisites
16
+
17
+ - Chrome is running
18
+ - You are already logged into [doubao.com](https://www.doubao.com/)
19
+ - Playwright MCP Bridge / browser bridge is configured for OpenCLI
20
+
21
+ ## Examples
22
+
23
+ ```bash
24
+ opencli doubao status
25
+ opencli doubao new
26
+ opencli doubao send "帮我总结这段文档"
27
+ opencli doubao read
28
+ opencli doubao ask "请写一个 Python 快速排序示例" --timeout 90
29
+ ```
30
+
31
+ ## Notes
32
+
33
+ - The adapter targets the web chat page at `https://www.doubao.com/chat`
34
+ - `new` first tries the visible "New Chat / 新对话" button, then falls back to the new-thread route
35
+ - `ask` uses DOM polling, so very long generations may need a larger `--timeout`
@@ -6,19 +6,35 @@
6
6
 
7
7
  | Command | Description |
8
8
  |---------|-------------|
9
- | `opencli hackernews top` | |
9
+ | `opencli hackernews top` | Hacker News top stories |
10
+ | `opencli hackernews new` | Hacker News newest stories |
11
+ | `opencli hackernews best` | Hacker News best stories |
12
+ | `opencli hackernews ask` | Hacker News Ask HN posts |
13
+ | `opencli hackernews show` | Hacker News Show HN posts |
14
+ | `opencli hackernews jobs` | Hacker News job postings |
15
+ | `opencli hackernews search <query>` | Search Hacker News stories |
16
+ | `opencli hackernews user <username>` | Hacker News user profile |
10
17
 
11
18
  ## Usage Examples
12
19
 
13
20
  ```bash
14
- # Quick start
21
+ # Top stories
15
22
  opencli hackernews top --limit 5
16
23
 
24
+ # Newest stories
25
+ opencli hackernews new --limit 10
26
+
27
+ # Search stories
28
+ opencli hackernews search "machine learning" --limit 5
29
+
30
+ # User profile
31
+ opencli hackernews user pg
32
+
17
33
  # JSON output
18
34
  opencli hackernews top -f json
19
35
 
20
- # Verbose mode
21
- opencli hackernews top -v
36
+ # Sort search by date
37
+ opencli hackernews search "rust" --sort date
22
38
  ```
23
39
 
24
40
  ## Prerequisites
@@ -29,7 +29,7 @@
29
29
  opencli tiktok profile --username tiktok
30
30
 
31
31
  # Search videos
32
- opencli tiktok search --query "cooking" --limit 10
32
+ opencli tiktok search "cooking" --limit 10
33
33
 
34
34
  # Trending explore videos
35
35
  opencli tiktok explore --limit 20
@@ -6,27 +6,48 @@
6
6
 
7
7
  | Command | Description |
8
8
  |---------|-------------|
9
- | `opencli v2ex hot` | |
10
- | `opencli v2ex latest` | |
11
- | `opencli v2ex topic` | |
12
- | `opencli v2ex daily` | |
13
- | `opencli v2ex me` | |
14
- | `opencli v2ex notifications` | |
9
+ | `opencli v2ex hot` | Hot topics |
10
+ | `opencli v2ex latest` | Latest topics |
11
+ | `opencli v2ex topic <id>` | Topic detail |
12
+ | `opencli v2ex node <name>` | Topics by node |
13
+ | `opencli v2ex user <username>` | Topics by user |
14
+ | `opencli v2ex member <username>` | User profile |
15
+ | `opencli v2ex replies <id>` | Topic replies |
16
+ | `opencli v2ex nodes` | All nodes (sorted by topic count) |
17
+ | `opencli v2ex daily` | Daily hot |
18
+ | `opencli v2ex me` | My profile (auth required) |
19
+ | `opencli v2ex notifications` | My notifications (auth required) |
15
20
 
16
21
  ## Usage Examples
17
22
 
18
23
  ```bash
19
- # Quick start
24
+ # Hot topics
20
25
  opencli v2ex hot --limit 5
21
26
 
27
+ # Browse topics in a node
28
+ opencli v2ex node python
29
+
30
+ # View topic replies
31
+ opencli v2ex replies 1000
32
+
33
+ # User's topics
34
+ opencli v2ex user Livid
35
+
36
+ # User profile
37
+ opencli v2ex member Livid
38
+
39
+ # List all nodes
40
+ opencli v2ex nodes --limit 10
41
+
22
42
  # JSON output
23
43
  opencli v2ex hot -f json
24
-
25
- # Verbose mode
26
- opencli v2ex hot -v
27
44
  ```
28
45
 
29
46
  ## Prerequisites
30
47
 
48
+ Most commands (`hot`, `latest`, `topic`, `node`, `user`, `member`, `replies`, `nodes`) use the public V2EX API and **require no browser or login**.
49
+
50
+ For `daily`, `me`, and `notifications`:
51
+
31
52
  - Chrome running and **logged into** v2ex.com
32
53
  - [Browser Bridge extension](/guide/browser-bridge) installed
@@ -7,6 +7,7 @@
7
7
  | Command | Description |
8
8
  |---------|-------------|
9
9
  | `opencli weibo hot` | |
10
+ | `opencli weibo search` | Search Weibo posts by keyword |
10
11
 
11
12
  ## Usage Examples
12
13
 
@@ -17,6 +18,9 @@ opencli weibo hot --limit 5
17
18
  # JSON output
18
19
  opencli weibo hot -f json
19
20
 
21
+ # Search
22
+ opencli weibo search "OpenAI" --limit 5
23
+
20
24
  # Verbose mode
21
25
  opencli weibo hot -v
22
26
  ```
@@ -0,0 +1,33 @@
1
+ # WeChat (微信公众号)
2
+
3
+ **Mode**: 🔐 Browser · **Domain**: `mp.weixin.qq.com`
4
+
5
+ ## Commands
6
+
7
+ | Command | Description |
8
+ |---------|-------------|
9
+ | `opencli weixin download` | 下载微信公众号文章为 Markdown 格式 |
10
+
11
+ ## Usage Examples
12
+
13
+ ```bash
14
+ # Export article to Markdown
15
+ opencli weixin download --url "https://mp.weixin.qq.com/s/xxx" --output ./weixin
16
+
17
+ # Export with locally downloaded images
18
+ opencli weixin download --url "https://mp.weixin.qq.com/s/xxx" --download-images
19
+
20
+ # Export without images
21
+ opencli weixin download --url "https://mp.weixin.qq.com/s/xxx" --no-download-images
22
+ ```
23
+
24
+ ## Output
25
+
26
+ Downloads to `<output>/<article-title>/`:
27
+ - `<article-title>.md` — Markdown with frontmatter (title, author, publish time, source URL)
28
+ - `images/` — Downloaded images (if `--download-images` is enabled, default: true)
29
+
30
+ ## Prerequisites
31
+
32
+ - Chrome running and **logged into** mp.weixin.qq.com (for articles behind login wall)
33
+ - [Browser Bridge extension](/guide/browser-bridge) installed
@@ -6,7 +6,7 @@
6
6
 
7
7
  | Command | Description |
8
8
  |---------|-------------|
9
- | `opencli xiaohongshu search` | |
9
+ | `opencli xiaohongshu search` | Search notes by keyword (returns title, author, likes, URL) |
10
10
  | `opencli xiaohongshu notifications` | |
11
11
  | `opencli xiaohongshu feed` | |
12
12
  | `opencli xiaohongshu user` | |
@@ -20,14 +20,16 @@
20
20
  ## Usage Examples
21
21
 
22
22
  ```bash
23
- # Quick start
24
- opencli xiaohongshu search --limit 5
23
+ # Search for notes
24
+ opencli xiaohongshu search 美食 --limit 10
25
25
 
26
26
  # JSON output
27
- opencli xiaohongshu search -f json
27
+ opencli xiaohongshu search 旅行 -f json
28
28
 
29
- # Verbose mode
30
- opencli xiaohongshu search -v
29
+ # Other commands
30
+ opencli xiaohongshu feed
31
+ opencli xiaohongshu notifications
32
+ opencli xiaohongshu download <url>
31
33
  ```
32
34
 
33
35
  ## Prerequisites
@@ -0,0 +1,69 @@
1
+ # Yollomi
2
+
3
+ **Mode**: 🔐 Browser · **Domain**: `yollomi.com`
4
+
5
+ AI image/video generation and editing on [yollomi.com](https://yollomi.com). Uses the same `/api/ai/*` routes as the web app; authentication is your **logged-in Chrome session** (NextAuth cookies).
6
+
7
+ ## Commands
8
+
9
+ | Command | Description |
10
+ |---------|-------------|
11
+ | `opencli yollomi generate` | Text-to-image / image-to-image |
12
+ | `opencli yollomi video` | Text-to-video / image-to-video |
13
+ | `opencli yollomi edit` | Qwen image edit (prompt + image) |
14
+ | `opencli yollomi upload` | Upload a local file → public URL for other commands |
15
+ | `opencli yollomi models` | List image / video / tool models and credit costs |
16
+ | `opencli yollomi remove-bg` | Remove background (free) |
17
+ | `opencli yollomi upscale` | Image upscaling |
18
+ | `opencli yollomi face-swap` | Face swap between two images |
19
+ | `opencli yollomi restore` | Photo restoration |
20
+ | `opencli yollomi try-on` | Virtual try-on |
21
+ | `opencli yollomi background` | AI background for product/object images |
22
+ | `opencli yollomi object-remover` | Remove objects (image + mask URLs) |
23
+
24
+ ## Usage Examples
25
+
26
+ ```bash
27
+ # List models
28
+ opencli yollomi models --type image
29
+
30
+ # Text-to-image (default model: z-image-turbo)
31
+ opencli yollomi generate "a red apple on a wooden table"
32
+
33
+ # Choose model and aspect ratio
34
+ opencli yollomi generate "sunset" --model flux-schnell --ratio 16:9
35
+
36
+ # Image-to-image: upload first, then pass URL
37
+ opencli yollomi upload ./photo.png
38
+ opencli yollomi generate "oil painting style" --model flux-2-pro --image "https://..."
39
+
40
+ # Video
41
+ opencli yollomi video "waves on a beach" --model kling-2-1
42
+
43
+ # Tools
44
+ opencli yollomi remove-bg https://example.com/image.png
45
+ opencli yollomi upscale https://example.com/image.png --scale 4
46
+ opencli yollomi edit https://example.com/in.png "make it vintage"
47
+ ```
48
+
49
+ ### Common options
50
+
51
+ | Option | Applies to | Description |
52
+ |--------|------------|-------------|
53
+ | `--model` | `generate`, `video` | Model id (see `yollomi models`) |
54
+ | `--ratio` | `generate`, `video` | Aspect ratio, e.g. `1:1`, `16:9` |
55
+ | `--image` | `generate`, `video` | Image URL for img2img / i2v |
56
+ | `--output` | Most | Output directory (default `./yollomi-output`) |
57
+ | `--no-download` | Several | Print URLs only, skip saving files |
58
+
59
+ ## Prerequisites
60
+
61
+ - Chrome running and **logged into** [yollomi.com](https://yollomi.com) (Google OAuth)
62
+ - [Browser Bridge extension](/guide/browser-bridge) installed; daemon connects on first command
63
+
64
+ The CLI ensures the automation tab is on `yollomi.com` before calling APIs (same-origin `fetch` with session cookies).
65
+
66
+ ## Notes
67
+
68
+ - **Credits**: Each model consumes account credits; insufficient credits returns HTTP 402.
69
+ - **Upload**: Local paths for tools are not accepted directly — use `yollomi upload` to get a URL, or pass an existing HTTPS image URL.
@@ -0,0 +1,35 @@
1
+ # Doubao App (豆包桌面版)
2
+
3
+ Control the **Doubao AI Desktop App** via Chrome DevTools Protocol (CDP).
4
+
5
+ ## Prerequisites
6
+
7
+ 1. Launch Doubao Desktop with remote debugging enabled:
8
+ ```bash
9
+ /Applications/Doubao.app/Contents/MacOS/Doubao --remote-debugging-port=9225
10
+ ```
11
+ 2. Set the CDP endpoint:
12
+ ```bash
13
+ export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9225"
14
+ ```
15
+
16
+ ## Commands
17
+
18
+ | Command | Description |
19
+ |---------|-------------|
20
+ | `opencli doubao-app status` | Check CDP connection status |
21
+ | `opencli doubao-app new` | Start a new conversation |
22
+ | `opencli doubao-app send "message"` | Send a message to the current chat |
23
+ | `opencli doubao-app read` | Read the latest assistant reply |
24
+ | `opencli doubao-app ask "message"` | Send a prompt and wait for the reply |
25
+ | `opencli doubao-app screenshot` | Capture a screenshot of the app window |
26
+ | `opencli doubao-app dump` | Export DOM and snapshot debug info |
27
+
28
+ ## How It Works
29
+
30
+ Connects to the Doubao Electron app via CDP, injecting JavaScript into the renderer process to control the chat UI — sending messages, reading replies, and capturing screenshots.
31
+
32
+ ## Limitations
33
+
34
+ - Requires Doubao Desktop to be launched with `--remote-debugging-port`
35
+ - macOS / Linux / Windows (Electron-based, platform independent)
@@ -10,30 +10,39 @@ Run `opencli list` for the live registry.
10
10
  | **[reddit](/adapters/browser/reddit)** | `hot` `frontpage` `popular` `search` `subreddit` `read` `user` `user-posts` `user-comments` `upvote` `save` `comment` `subscribe` `saved` `upvoted` | 🔐 Browser |
11
11
  | **[bilibili](/adapters/browser/bilibili)** | `hot` `search` `me` `favorite` `history` `feed` `subtitle` `dynamic` `ranking` `following` `user-videos` `download` | 🔐 Browser |
12
12
  | **[zhihu](/adapters/browser/zhihu)** | `hot` `search` `question` `download` | 🔐 Browser |
13
- | **[xiaohongshu](/adapters/browser/xiaohongshu)** | `search` `notifications` `feed` `me` `user` `download` | 🔐 Browser |
13
+ | **[xiaohongshu](/adapters/browser/xiaohongshu)** | `search` `notifications` `feed` `me` `user` `download` `publish` | 🔐 Browser |
14
14
  | **[xueqiu](/adapters/browser/xueqiu)** | `feed` `hot-stock` `hot` `search` `stock` `watchlist` | 🔐 Browser |
15
15
  | **[youtube](/adapters/browser/youtube)** | `search` `video` `transcript` | 🔐 Browser |
16
- | **[v2ex](/adapters/browser/v2ex)** | `hot` `latest` `topic` `daily` `me` `notifications` | 🌐 / 🔐 |
16
+ | **[v2ex](/adapters/browser/v2ex)** | `hot` `latest` `topic` `node` `user` `member` `replies` `nodes` `daily` `me` `notifications` | 🌐 / 🔐 |
17
17
  | **[bloomberg](/adapters/browser/bloomberg)** | `main` `markets` `economics` `industries` `tech` `politics` `businessweek` `opinions` `feeds` `news` | 🌐 / 🔐 |
18
- | **[weibo](/adapters/browser/weibo)** | `hot` | 🔐 Browser |
18
+ | **[weibo](/adapters/browser/weibo)** | `hot` `search` | 🔐 Browser |
19
19
  | **[linkedin](/adapters/browser/linkedin)** | `search` | 🔐 Browser |
20
20
  | **[coupang](/adapters/browser/coupang)** | `search` `add-to-cart` | 🔐 Browser |
21
- | **[boss](/adapters/browser/boss)** | `search` `detail` | 🔐 Browser |
21
+ | **[boss](/adapters/browser/boss)** | `search` `detail` `recommend` `joblist` `greet` `batchgreet` `send` `chatlist` `chatmsg` `invite` `mark` `exchange` `resume` `stats` | 🔐 Browser |
22
22
  | **[ctrip](/adapters/browser/ctrip)** | `search` | 🔐 Browser |
23
23
  | **[reuters](/adapters/browser/reuters)** | `search` | 🔐 Browser |
24
24
  | **[smzdm](/adapters/browser/smzdm)** | `search` | 🔐 Browser |
25
25
  | **[jike](/adapters/browser/jike)** | `feed` `search` `post` `topic` `user` `create` `comment` `like` `repost` `notifications` | 🔐 Browser |
26
26
  | **[jimeng](/adapters/browser/jimeng)** | `generate` `history` | 🔐 Browser |
27
+ | **[yollomi](/adapters/browser/yollomi)** | `generate` `video` `edit` `upload` `models` `remove-bg` `upscale` `face-swap` `restore` `try-on` `background` `object-remover` | 🔐 Browser |
27
28
  | **[linux-do](/adapters/browser/linux-do)** | `hot` `latest` `categories` `category` `search` `topic` | 🔐 Browser |
28
29
  | **[chaoxing](/adapters/browser/chaoxing)** | `assignments` `exams` | 🔐 Browser |
29
30
  | **[grok](/adapters/browser/grok)** | `ask` | 🔐 Browser |
31
+ | **[doubao](/adapters/browser/doubao)** | `status` `new` `send` `read` `ask` | 🔐 Browser |
30
32
  | **[weread](/adapters/browser/weread)** | `shelf` `search` `book` `ranking` `notebooks` `highlights` `notes` | 🔐 Browser |
33
+ | **[douban](/adapters/browser/douban)** | `search` `top250` `subject` `marks` `reviews` | 🔐 Browser |
34
+ | **[facebook](/adapters/browser/facebook)** | `feed` `profile` `search` `friends` `groups` `events` `notifications` `memories` `add-friend` `join-group` | 🔐 Browser |
35
+ | **[instagram](/adapters/browser/instagram)** | `explore` `profile` `search` `user` `followers` `following` `follow` `unfollow` `like` `unlike` `comment` `save` `unsave` `saved` | 🔐 Browser |
36
+ | **[medium](/adapters/browser/medium)** | `feed` `search` `user` `shared` | 🔐 Browser |
37
+ | **[sinablog](/adapters/browser/sinablog)** | `hot` `search` `article` `user` `shared` | 🔐 Browser |
38
+ | **[substack](/adapters/browser/substack)** | `feed` `search` `publication` `shared` | 🔐 Browser |
39
+ | **[tiktok](/adapters/browser/tiktok)** | `explore` `search` `profile` `user` `following` `follow` `unfollow` `like` `unlike` `comment` `save` `unsave` `live` `notifications` `friends` | 🔐 Browser |
31
40
 
32
41
  ## Public API Adapters
33
42
 
34
43
  | Site | Commands | Mode |
35
44
  |------|----------|------|
36
- | **[hackernews](/adapters/browser/hackernews)** | `top` | 🌐 Public |
45
+ | **[hackernews](/adapters/browser/hackernews)** | `top` `new` `best` `ask` `show` `jobs` `search` `user` | 🌐 Public |
37
46
  | **[bbc](/adapters/browser/bbc)** | `news` | 🌐 Public |
38
47
  | **[devto](/adapters/browser/devto)** | `top` `tag` `user` | 🌐 Public |
39
48
  | **[apple-podcasts](/adapters/browser/apple-podcasts)** | `search` `episodes` `top` | 🌐 Public |
@@ -45,6 +54,7 @@ Run `opencli list` for the live registry.
45
54
  | **[sinafinance](/adapters/browser/sinafinance)** | `news` | 🌐 Public |
46
55
  | **[stackoverflow](/adapters/browser/stackoverflow)** | `hot` `search` `bounties` `unanswered` | 🌐 Public |
47
56
  | **[wikipedia](/adapters/browser/wikipedia)** | `search` `summary` | 🌐 Public |
57
+ | **[lobsters](/adapters/browser/lobsters)** | `hot` `newest` `active` `tag` | 🌐 Public |
48
58
 
49
59
  ## Desktop Adapters
50
60
 
@@ -57,3 +67,4 @@ Run `opencli list` for the live registry.
57
67
  | **[ChatWise](/adapters/desktop/chatwise)** | Multi-LLM client | `status` `new` `send` `read` `ask` `model` `history` `export` `screenshot` |
58
68
  | **[Notion](/adapters/desktop/notion)** | Search, read, write pages | `status` `search` `read` `new` `write` `sidebar` `favorites` `export` |
59
69
  | **[Discord](/adapters/desktop/discord)** | Desktop messages & channels | `status` `send` `read` `channels` `servers` `search` `members` |
70
+ | **[Doubao App](/adapters/desktop/doubao-app)** | Doubao AI desktop app via CDP | `status` `new` `send` `read` `ask` `screenshot` `dump` |
@@ -10,6 +10,7 @@ OpenCLI supports downloading images, videos, and articles from supported platfor
10
10
  | **bilibili** | Videos | Requires `yt-dlp` installed |
11
11
  | **twitter** | Images, Videos | Downloads from user media tab or single tweet |
12
12
  | **zhihu** | Articles (Markdown) | Exports articles with optional image download |
13
+ | **weixin** | Articles (Markdown) | Exports WeChat Official Account articles |
13
14
 
14
15
  ## Prerequisites
15
16
 
@@ -43,6 +44,9 @@ opencli zhihu download "https://zhuanlan.zhihu.com/p/xxx" --output ./zhihu
43
44
 
44
45
  # Export with local images
45
46
  opencli zhihu download "https://zhuanlan.zhihu.com/p/xxx" --download-images
47
+
48
+ # Export WeChat article to Markdown
49
+ opencli weixin download --url "https://mp.weixin.qq.com/s/xxx" --output ./weixin
46
50
  ```
47
51
 
48
52
  ## Pipeline Step (YAML Adapters)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jackwener/opencli",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -53,11 +53,13 @@
53
53
  "cli-table3": "^0.6.5",
54
54
  "commander": "^14.0.3",
55
55
  "js-yaml": "^4.1.0",
56
+ "turndown": "^7.2.2",
56
57
  "ws": "^8.18.0"
57
58
  },
58
59
  "devDependencies": {
59
60
  "@types/js-yaml": "^4.0.9",
60
61
  "@types/node": "^22.13.10",
62
+ "@types/turndown": "^5.0.6",
61
63
  "@types/ws": "^8.5.13",
62
64
  "tsx": "^4.19.3",
63
65
  "typescript": "^5.8.2",
@@ -5,31 +5,37 @@
5
5
  * The daemon architecture has a single failure mode: daemon not reachable or extension not connected.
6
6
  */
7
7
 
8
+ import { BrowserConnectError } from '../errors.js';
9
+
8
10
  export type ConnectFailureKind = 'daemon-not-running' | 'extension-not-connected' | 'command-failed' | 'unknown';
9
11
 
10
- export function formatBrowserConnectError(kind: ConnectFailureKind, detail?: string): Error {
12
+ export function formatBrowserConnectError(kind: ConnectFailureKind, detail?: string): BrowserConnectError {
11
13
  switch (kind) {
12
14
  case 'daemon-not-running':
13
- return new Error(
14
- 'Cannot connect to opencli daemon.\n\n' +
15
+ return new BrowserConnectError(
16
+ 'Cannot connect to opencli daemon.' +
17
+ (detail ? `\n\n${detail}` : ''),
15
18
  'The daemon should start automatically. If it doesn\'t, try:\n' +
16
19
  ' node dist/daemon.js\n' +
17
- 'Make sure port 19825 is available.' +
18
- (detail ? `\n\n${detail}` : ''),
20
+ 'Make sure port 19825 is available.',
19
21
  );
20
22
  case 'extension-not-connected':
21
- return new Error(
22
- 'opencli Browser Bridge extension is not connected.\n\n' +
23
+ return new BrowserConnectError(
24
+ 'opencli Browser Bridge extension is not connected.' +
25
+ (detail ? `\n\n${detail}` : ''),
23
26
  'Please install the extension:\n' +
24
27
  ' 1. Download from GitHub Releases\n' +
25
28
  ' 2. Open chrome://extensions/ → Enable Developer Mode\n' +
26
29
  ' 3. Click "Load unpacked" → select the extension folder\n' +
27
- ' 4. Make sure Chrome is running' +
28
- (detail ? `\n\n${detail}` : ''),
30
+ ' 4. Make sure Chrome is running',
29
31
  );
30
32
  case 'command-failed':
31
- return new Error(`Browser command failed: ${detail ?? 'unknown error'}`);
33
+ return new BrowserConnectError(
34
+ `Browser command failed: ${detail ?? 'unknown error'}`,
35
+ );
32
36
  default:
33
- return new Error(detail ?? 'Failed to connect to browser');
37
+ return new BrowserConnectError(
38
+ detail ?? 'Failed to connect to browser',
39
+ );
34
40
  }
35
41
  }
@@ -13,6 +13,7 @@ import * as fs from 'node:fs';
13
13
  import * as path from 'node:path';
14
14
  import { fileURLToPath, pathToFileURL } from 'node:url';
15
15
  import yaml from 'js-yaml';
16
+ import { getErrorMessage } from './errors.js';
16
17
 
17
18
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
18
19
  const CLIS_DIR = path.resolve(__dirname, 'clis');
@@ -73,9 +74,7 @@ function isRecord(value: unknown): value is Record<string, unknown> {
73
74
  return typeof value === 'object' && value !== null && !Array.isArray(value);
74
75
  }
75
76
 
76
- function getErrorMessage(error: unknown): string {
77
- return error instanceof Error ? error.message : String(error);
78
- }
77
+
79
78
 
80
79
  function extractBalancedBlock(
81
80
  source: string,
package/src/cli.ts CHANGED
@@ -183,6 +183,30 @@ export function runCli(BUILTIN_CLIS: string, USER_CLIS: string): void {
183
183
  process.exitCode = r.ok ? 0 : 1;
184
184
  });
185
185
 
186
+ // ── Built-in: record ─────────────────────────────────────────────────────
187
+
188
+ program
189
+ .command('record')
190
+ .description('Record API calls from a live browser session → generate YAML candidates')
191
+ .argument('<url>', 'URL to open and record')
192
+ .option('--site <name>', 'Site name (inferred from URL if omitted)')
193
+ .option('--out <dir>', 'Output directory for candidates')
194
+ .option('--poll <ms>', 'Poll interval in milliseconds', '2000')
195
+ .option('--timeout <ms>', 'Auto-stop after N milliseconds (default: 60000)', '60000')
196
+ .action(async (url, opts) => {
197
+ const { recordSession, renderRecordSummary } = await import('./record.js');
198
+ const result = await recordSession({
199
+ BrowserFactory: getBrowserFactory(),
200
+ url,
201
+ site: opts.site,
202
+ outDir: opts.out,
203
+ pollMs: parseInt(opts.poll, 10),
204
+ timeoutMs: parseInt(opts.timeout, 10),
205
+ });
206
+ console.log(renderRecordSummary(result));
207
+ process.exitCode = result.candidateCount > 0 ? 0 : 1;
208
+ });
209
+
186
210
  program
187
211
  .command('cascade')
188
212
  .description('Strategy cascade: find simplest working strategy')
@@ -233,10 +257,11 @@ export function runCli(BUILTIN_CLIS: string, USER_CLIS: string): void {
233
257
  .argument('<source>', 'Plugin source (e.g. github:user/repo)')
234
258
  .action(async (source: string) => {
235
259
  const { installPlugin } = await import('./plugin.js');
260
+ const { discoverPlugins } = await import('./discovery.js');
236
261
  try {
237
262
  const name = installPlugin(source);
238
- console.log(chalk.green(`✅ Plugin "${name}" installed successfully.`));
239
- console.log(chalk.dim(` Restart opencli to use the new commands.`));
263
+ await discoverPlugins();
264
+ console.log(chalk.green(`✅ Plugin "${name}" installed successfully. Commands are ready to use.`));
240
265
  } catch (err: any) {
241
266
  console.error(chalk.red(`Error: ${err.message}`));
242
267
  process.exitCode = 1;
@@ -258,6 +283,24 @@ export function runCli(BUILTIN_CLIS: string, USER_CLIS: string): void {
258
283
  }
259
284
  });
260
285
 
286
+ pluginCmd
287
+ .command('update')
288
+ .description('Update a plugin to the latest version')
289
+ .argument('<name>', 'Plugin name')
290
+ .action(async (name: string) => {
291
+ const { updatePlugin } = await import('./plugin.js');
292
+ const { discoverPlugins } = await import('./discovery.js');
293
+ try {
294
+ updatePlugin(name);
295
+ await discoverPlugins();
296
+ console.log(chalk.green(`✅ Plugin "${name}" updated successfully.`));
297
+ } catch (err: any) {
298
+ console.error(chalk.red(`Error: ${err.message}`));
299
+ process.exitCode = 1;
300
+ }
301
+ });
302
+
303
+
261
304
  pluginCmd
262
305
  .command('list')
263
306
  .description('List installed plugins')