@jackwener/opencli 1.4.1 → 1.5.1

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 (369) hide show
  1. package/.github/workflows/build-extension.yml +2 -6
  2. package/.github/workflows/ci.yml +21 -1
  3. package/README.md +35 -6
  4. package/README.zh-CN.md +12 -5
  5. package/SKILL.md +2 -0
  6. package/dist/browser/cdp.d.ts +2 -1
  7. package/dist/browser/cdp.js +5 -0
  8. package/dist/browser/discover.d.ts +4 -1
  9. package/dist/browser/discover.js +6 -2
  10. package/dist/browser/errors.d.ts +2 -2
  11. package/dist/browser/errors.js +4 -12
  12. package/dist/browser/mcp.d.ts +2 -1
  13. package/dist/browser/page.d.ts +3 -0
  14. package/dist/browser/page.js +24 -1
  15. package/dist/build-manifest.d.ts +2 -0
  16. package/dist/build-manifest.js +39 -14
  17. package/dist/build-manifest.test.js +21 -0
  18. package/dist/capabilityRouting.d.ts +2 -0
  19. package/dist/capabilityRouting.js +2 -1
  20. package/dist/cli-manifest.json +1567 -108
  21. package/dist/cli.js +68 -6
  22. package/dist/clis/36kr/article.d.ts +1 -0
  23. package/dist/clis/36kr/article.js +62 -0
  24. package/dist/clis/36kr/hot.d.ts +3 -0
  25. package/dist/clis/36kr/hot.js +80 -0
  26. package/dist/clis/36kr/hot.test.d.ts +1 -0
  27. package/dist/clis/36kr/hot.test.js +15 -0
  28. package/dist/clis/36kr/news.d.ts +1 -0
  29. package/dist/clis/36kr/news.js +51 -0
  30. package/dist/clis/36kr/news.test.d.ts +1 -0
  31. package/dist/clis/36kr/news.test.js +85 -0
  32. package/dist/clis/36kr/search.d.ts +1 -0
  33. package/dist/clis/36kr/search.js +72 -0
  34. package/dist/clis/bilibili/comments.d.ts +5 -0
  35. package/dist/clis/bilibili/comments.js +40 -0
  36. package/dist/clis/bilibili/comments.test.d.ts +1 -0
  37. package/dist/clis/bilibili/comments.test.js +82 -0
  38. package/dist/clis/bluesky/feeds.yaml +29 -0
  39. package/dist/clis/bluesky/followers.yaml +33 -0
  40. package/dist/clis/bluesky/following.yaml +33 -0
  41. package/dist/clis/bluesky/profile.yaml +27 -0
  42. package/dist/clis/bluesky/search.yaml +34 -0
  43. package/dist/clis/bluesky/starter-packs.yaml +34 -0
  44. package/dist/clis/bluesky/thread.yaml +32 -0
  45. package/dist/clis/bluesky/trending.yaml +27 -0
  46. package/dist/clis/bluesky/user.yaml +34 -0
  47. package/dist/clis/chatgpt/ask.js +29 -14
  48. package/dist/clis/chatgpt/ax.d.ts +6 -0
  49. package/dist/clis/chatgpt/ax.js +172 -1
  50. package/dist/clis/chatgpt/model.d.ts +1 -0
  51. package/dist/clis/chatgpt/model.js +24 -0
  52. package/dist/clis/chatgpt/send.js +12 -3
  53. package/dist/clis/douban/download.d.ts +1 -0
  54. package/dist/clis/douban/download.js +67 -0
  55. package/dist/clis/douban/download.test.d.ts +1 -0
  56. package/dist/clis/douban/download.test.js +170 -0
  57. package/dist/clis/douban/photos.d.ts +1 -0
  58. package/dist/clis/douban/photos.js +34 -0
  59. package/dist/clis/douban/utils.d.ts +25 -0
  60. package/dist/clis/douban/utils.js +190 -1
  61. package/dist/clis/douban/utils.test.d.ts +1 -0
  62. package/dist/clis/douban/utils.test.js +64 -0
  63. package/dist/clis/imdb/person.d.ts +1 -0
  64. package/dist/clis/imdb/person.js +203 -0
  65. package/dist/clis/imdb/reviews.d.ts +1 -0
  66. package/dist/clis/imdb/reviews.js +88 -0
  67. package/dist/clis/imdb/search.d.ts +1 -0
  68. package/dist/clis/imdb/search.js +161 -0
  69. package/dist/clis/imdb/title.d.ts +1 -0
  70. package/dist/clis/imdb/title.js +93 -0
  71. package/dist/clis/imdb/top.d.ts +1 -0
  72. package/dist/clis/imdb/top.js +53 -0
  73. package/dist/clis/imdb/trending.d.ts +1 -0
  74. package/dist/clis/imdb/trending.js +52 -0
  75. package/dist/clis/imdb/utils.d.ts +46 -0
  76. package/dist/clis/imdb/utils.js +285 -0
  77. package/dist/clis/imdb/utils.test.d.ts +1 -0
  78. package/dist/clis/imdb/utils.test.js +88 -0
  79. package/dist/clis/jd/item.d.ts +4 -0
  80. package/dist/clis/jd/item.js +16 -15
  81. package/dist/clis/jd/item.test.js +16 -1
  82. package/dist/clis/linux-do/categories.yaml +38 -9
  83. package/dist/clis/linux-do/category.d.ts +1 -0
  84. package/dist/clis/linux-do/category.js +36 -0
  85. package/dist/clis/linux-do/feed.d.ts +45 -0
  86. package/dist/clis/linux-do/feed.js +397 -0
  87. package/dist/clis/linux-do/feed.test.d.ts +1 -0
  88. package/dist/clis/linux-do/feed.test.js +118 -0
  89. package/dist/clis/linux-do/hot.d.ts +1 -0
  90. package/dist/clis/linux-do/hot.js +25 -0
  91. package/dist/clis/linux-do/latest.d.ts +1 -0
  92. package/dist/clis/linux-do/latest.js +18 -0
  93. package/dist/clis/linux-do/tags.yaml +41 -0
  94. package/dist/clis/linux-do/topic.yaml +41 -3
  95. package/dist/clis/linux-do/user-posts.yaml +67 -0
  96. package/dist/clis/linux-do/user-topics.yaml +54 -0
  97. package/dist/clis/paperreview/commands.test.d.ts +3 -0
  98. package/dist/clis/paperreview/commands.test.js +243 -0
  99. package/dist/clis/paperreview/feedback.d.ts +1 -0
  100. package/dist/clis/paperreview/feedback.js +52 -0
  101. package/dist/clis/paperreview/review.d.ts +1 -0
  102. package/dist/clis/paperreview/review.js +37 -0
  103. package/dist/clis/paperreview/submit.d.ts +1 -0
  104. package/dist/clis/paperreview/submit.js +85 -0
  105. package/dist/clis/paperreview/utils.d.ts +46 -0
  106. package/dist/clis/paperreview/utils.js +197 -0
  107. package/dist/clis/paperreview/utils.test.d.ts +1 -0
  108. package/dist/clis/paperreview/utils.test.js +49 -0
  109. package/dist/clis/producthunt/browse.d.ts +1 -0
  110. package/dist/clis/producthunt/browse.js +99 -0
  111. package/dist/clis/producthunt/hot.d.ts +1 -0
  112. package/dist/clis/producthunt/hot.js +110 -0
  113. package/dist/clis/producthunt/posts.d.ts +1 -0
  114. package/dist/clis/producthunt/posts.js +28 -0
  115. package/dist/clis/producthunt/today.d.ts +1 -0
  116. package/dist/clis/producthunt/today.js +35 -0
  117. package/dist/clis/producthunt/utils.d.ts +29 -0
  118. package/dist/clis/producthunt/utils.js +99 -0
  119. package/dist/clis/producthunt/utils.test.d.ts +1 -0
  120. package/dist/clis/producthunt/utils.test.js +64 -0
  121. package/dist/clis/twitter/article.js +4 -28
  122. package/dist/clis/twitter/likes.d.ts +24 -0
  123. package/dist/clis/twitter/likes.js +217 -0
  124. package/dist/clis/twitter/likes.test.d.ts +1 -0
  125. package/dist/clis/twitter/likes.test.js +85 -0
  126. package/dist/clis/twitter/profile.js +4 -28
  127. package/dist/clis/twitter/search.js +2 -1
  128. package/dist/clis/twitter/search.test.js +2 -0
  129. package/dist/clis/twitter/shared.d.ts +6 -0
  130. package/dist/clis/twitter/shared.js +35 -0
  131. package/dist/clis/twitter/timeline.js +2 -13
  132. package/dist/clis/twitter/trending.js +29 -61
  133. package/dist/clis/v2ex/hot.yaml +17 -3
  134. package/dist/clis/weixin/download.d.ts +17 -0
  135. package/dist/clis/weixin/download.js +88 -20
  136. package/dist/clis/weread/book.js +2 -2
  137. package/dist/clis/weread/commands.test.d.ts +3 -0
  138. package/dist/clis/weread/commands.test.js +43 -0
  139. package/dist/clis/weread/highlights.js +2 -2
  140. package/dist/clis/weread/notebooks.js +2 -2
  141. package/dist/clis/weread/notes.js +3 -3
  142. package/dist/clis/weread/shelf.js +2 -2
  143. package/dist/clis/weread/utils.d.ts +4 -4
  144. package/dist/clis/weread/utils.js +32 -14
  145. package/dist/clis/weread/utils.test.js +1 -28
  146. package/dist/clis/xiaohongshu/comments.d.ts +5 -0
  147. package/dist/clis/xiaohongshu/comments.js +74 -0
  148. package/dist/clis/xiaohongshu/comments.test.d.ts +1 -0
  149. package/dist/clis/xiaohongshu/comments.test.js +79 -0
  150. package/dist/clis/xiaohongshu/publish.js +179 -47
  151. package/dist/clis/xiaohongshu/publish.test.d.ts +1 -0
  152. package/dist/clis/xiaohongshu/publish.test.js +131 -0
  153. package/dist/clis/xiaohongshu/search.d.ts +8 -1
  154. package/dist/clis/xiaohongshu/search.js +20 -1
  155. package/dist/clis/xiaohongshu/search.test.d.ts +1 -1
  156. package/dist/clis/xiaohongshu/search.test.js +32 -1
  157. package/dist/commanderAdapter.d.ts +1 -0
  158. package/dist/commanderAdapter.js +176 -29
  159. package/dist/commanderAdapter.test.d.ts +1 -0
  160. package/dist/commanderAdapter.test.js +62 -0
  161. package/dist/daemon.js +17 -1
  162. package/dist/discovery.js +48 -42
  163. package/dist/doctor.d.ts +2 -2
  164. package/dist/doctor.js +11 -4
  165. package/dist/download/index.js +63 -51
  166. package/dist/download/index.test.js +17 -4
  167. package/dist/engine.test.js +42 -0
  168. package/dist/errors.d.ts +4 -2
  169. package/dist/errors.js +17 -34
  170. package/dist/execution.d.ts +1 -3
  171. package/dist/execution.js +66 -8
  172. package/dist/execution.test.d.ts +1 -0
  173. package/dist/execution.test.js +40 -0
  174. package/dist/external.js +6 -1
  175. package/dist/hooks.js +2 -0
  176. package/dist/main.js +6 -0
  177. package/dist/output.js +5 -1
  178. package/dist/pipeline/executor.js +3 -4
  179. package/dist/plugin-manifest.d.ts +70 -0
  180. package/dist/plugin-manifest.js +160 -0
  181. package/dist/plugin-manifest.test.d.ts +4 -0
  182. package/dist/plugin-manifest.test.js +179 -0
  183. package/dist/plugin-scaffold.d.ts +28 -0
  184. package/dist/plugin-scaffold.js +142 -0
  185. package/dist/plugin-scaffold.test.d.ts +4 -0
  186. package/dist/plugin-scaffold.test.js +83 -0
  187. package/dist/plugin.d.ts +82 -11
  188. package/dist/plugin.js +870 -84
  189. package/dist/plugin.test.js +1032 -17
  190. package/dist/registry.d.ts +4 -0
  191. package/dist/registry.js +2 -0
  192. package/dist/runtime-detect.d.ts +21 -0
  193. package/dist/runtime-detect.js +32 -0
  194. package/dist/runtime-detect.test.d.ts +1 -0
  195. package/dist/runtime-detect.test.js +27 -0
  196. package/dist/runtime.d.ts +1 -0
  197. package/dist/runtime.js +2 -2
  198. package/dist/serialization.d.ts +2 -0
  199. package/dist/serialization.js +6 -0
  200. package/dist/types.d.ts +3 -0
  201. package/dist/update-check.d.ts +22 -0
  202. package/dist/update-check.js +112 -0
  203. package/dist/weixin-download.test.d.ts +1 -0
  204. package/dist/weixin-download.test.js +30 -0
  205. package/dist/weread-private-api-regression.test.d.ts +1 -0
  206. package/dist/weread-private-api-regression.test.js +122 -0
  207. package/dist/yaml-schema.d.ts +3 -0
  208. package/dist/yaml-schema.js +18 -1
  209. package/docs/.vitepress/config.mts +4 -0
  210. package/docs/adapters/browser/36kr.md +47 -0
  211. package/docs/adapters/browser/bluesky.md +53 -0
  212. package/docs/adapters/browser/douban.md +14 -0
  213. package/docs/adapters/browser/imdb.md +47 -0
  214. package/docs/adapters/browser/jd.md +2 -2
  215. package/docs/adapters/browser/linux-do.md +181 -20
  216. package/docs/adapters/browser/paperreview.md +43 -0
  217. package/docs/adapters/browser/producthunt.md +49 -0
  218. package/docs/adapters/desktop/chatgpt.md +5 -0
  219. package/docs/adapters/index.md +6 -2
  220. package/docs/advanced/download.md +4 -0
  221. package/docs/advanced/rate-limiter-plugin.md +99 -0
  222. package/docs/guide/electron-app-cli.md +200 -0
  223. package/docs/guide/getting-started.md +1 -0
  224. package/docs/guide/plugins.md +97 -0
  225. package/docs/zh/guide/electron-app-cli.md +188 -0
  226. package/docs/zh/guide/getting-started.md +1 -0
  227. package/docs/zh/guide/plugins.md +65 -0
  228. package/extension/package.json +1 -0
  229. package/extension/scripts/package-release.mjs +179 -0
  230. package/extension/src/background.ts +2 -0
  231. package/package.json +4 -1
  232. package/scripts/postinstall.js +10 -0
  233. package/src/browser/cdp.ts +8 -1
  234. package/src/browser/discover.ts +8 -3
  235. package/src/browser/errors.ts +13 -14
  236. package/src/browser/mcp.ts +2 -1
  237. package/src/browser/page.ts +24 -1
  238. package/src/build-manifest.test.ts +23 -0
  239. package/src/build-manifest.ts +40 -15
  240. package/src/capabilityRouting.ts +2 -1
  241. package/src/cli.ts +69 -6
  242. package/src/clis/36kr/article.ts +69 -0
  243. package/src/clis/36kr/hot.test.ts +19 -0
  244. package/src/clis/36kr/hot.ts +100 -0
  245. package/src/clis/36kr/news.test.ts +90 -0
  246. package/src/clis/36kr/news.ts +54 -0
  247. package/src/clis/36kr/search.ts +78 -0
  248. package/src/clis/bilibili/comments.test.ts +102 -0
  249. package/src/clis/bilibili/comments.ts +44 -0
  250. package/src/clis/bluesky/feeds.yaml +29 -0
  251. package/src/clis/bluesky/followers.yaml +33 -0
  252. package/src/clis/bluesky/following.yaml +33 -0
  253. package/src/clis/bluesky/profile.yaml +27 -0
  254. package/src/clis/bluesky/search.yaml +34 -0
  255. package/src/clis/bluesky/starter-packs.yaml +34 -0
  256. package/src/clis/bluesky/thread.yaml +32 -0
  257. package/src/clis/bluesky/trending.yaml +27 -0
  258. package/src/clis/bluesky/user.yaml +34 -0
  259. package/src/clis/chatgpt/ask.ts +28 -14
  260. package/src/clis/chatgpt/ax.ts +180 -1
  261. package/src/clis/chatgpt/model.ts +27 -0
  262. package/src/clis/chatgpt/send.ts +16 -6
  263. package/src/clis/douban/download.test.ts +196 -0
  264. package/src/clis/douban/download.ts +78 -0
  265. package/src/clis/douban/photos.ts +36 -0
  266. package/src/clis/douban/utils.test.ts +97 -0
  267. package/src/clis/douban/utils.ts +232 -1
  268. package/src/clis/imdb/person.ts +232 -0
  269. package/src/clis/imdb/reviews.ts +111 -0
  270. package/src/clis/imdb/search.ts +179 -0
  271. package/src/clis/imdb/title.ts +121 -0
  272. package/src/clis/imdb/top.ts +67 -0
  273. package/src/clis/imdb/trending.ts +66 -0
  274. package/src/clis/imdb/utils.test.ts +117 -0
  275. package/src/clis/imdb/utils.ts +305 -0
  276. package/src/clis/jd/item.test.ts +18 -1
  277. package/src/clis/jd/item.ts +18 -15
  278. package/src/clis/linux-do/categories.yaml +38 -9
  279. package/src/clis/linux-do/category.ts +37 -0
  280. package/src/clis/linux-do/feed.test.ts +132 -0
  281. package/src/clis/linux-do/feed.ts +501 -0
  282. package/src/clis/linux-do/hot.ts +26 -0
  283. package/src/clis/linux-do/latest.ts +19 -0
  284. package/src/clis/linux-do/tags.yaml +41 -0
  285. package/src/clis/linux-do/topic.yaml +41 -3
  286. package/src/clis/linux-do/user-posts.yaml +67 -0
  287. package/src/clis/linux-do/user-topics.yaml +54 -0
  288. package/src/clis/paperreview/commands.test.ts +283 -0
  289. package/src/clis/paperreview/feedback.ts +64 -0
  290. package/src/clis/paperreview/review.ts +47 -0
  291. package/src/clis/paperreview/submit.ts +119 -0
  292. package/src/clis/paperreview/utils.test.ts +68 -0
  293. package/src/clis/paperreview/utils.ts +276 -0
  294. package/src/clis/producthunt/browse.ts +109 -0
  295. package/src/clis/producthunt/hot.ts +127 -0
  296. package/src/clis/producthunt/posts.ts +29 -0
  297. package/src/clis/producthunt/today.ts +37 -0
  298. package/src/clis/producthunt/utils.test.ts +72 -0
  299. package/src/clis/producthunt/utils.ts +122 -0
  300. package/src/clis/twitter/article.ts +5 -28
  301. package/src/clis/twitter/likes.test.ts +91 -0
  302. package/src/clis/twitter/likes.ts +256 -0
  303. package/src/clis/twitter/profile.ts +5 -28
  304. package/src/clis/twitter/search.test.ts +2 -0
  305. package/src/clis/twitter/search.ts +3 -1
  306. package/src/clis/twitter/shared.ts +45 -0
  307. package/src/clis/twitter/timeline.ts +2 -13
  308. package/src/clis/twitter/trending.ts +29 -77
  309. package/src/clis/v2ex/hot.yaml +17 -3
  310. package/src/clis/weixin/download.ts +114 -20
  311. package/src/clis/weread/book.ts +2 -2
  312. package/src/clis/weread/commands.test.ts +57 -0
  313. package/src/clis/weread/highlights.ts +2 -2
  314. package/src/clis/weread/notebooks.ts +2 -2
  315. package/src/clis/weread/notes.ts +3 -3
  316. package/src/clis/weread/shelf.ts +2 -2
  317. package/src/clis/weread/utils.test.ts +1 -32
  318. package/src/clis/weread/utils.ts +41 -16
  319. package/src/clis/xiaohongshu/comments.test.ts +96 -0
  320. package/src/clis/xiaohongshu/comments.ts +81 -0
  321. package/src/clis/xiaohongshu/publish.test.ts +151 -0
  322. package/src/clis/xiaohongshu/publish.ts +206 -54
  323. package/src/clis/xiaohongshu/search.test.ts +39 -1
  324. package/src/clis/xiaohongshu/search.ts +19 -1
  325. package/src/commanderAdapter.test.ts +78 -0
  326. package/src/commanderAdapter.ts +188 -24
  327. package/src/daemon.ts +19 -1
  328. package/src/discovery.ts +49 -48
  329. package/src/doctor.ts +15 -5
  330. package/src/download/index.test.ts +14 -4
  331. package/src/download/index.ts +67 -55
  332. package/src/engine.test.ts +38 -0
  333. package/src/errors.ts +26 -63
  334. package/src/execution.test.ts +47 -0
  335. package/src/execution.ts +67 -9
  336. package/src/external.ts +6 -1
  337. package/src/hooks.ts +1 -0
  338. package/src/main.ts +7 -0
  339. package/src/output.ts +3 -1
  340. package/src/pipeline/executor.ts +4 -6
  341. package/src/plugin-manifest.test.ts +223 -0
  342. package/src/plugin-manifest.ts +206 -0
  343. package/src/plugin-scaffold.test.ts +98 -0
  344. package/src/plugin-scaffold.ts +170 -0
  345. package/src/plugin.test.ts +1104 -17
  346. package/src/plugin.ts +1101 -86
  347. package/src/registry.ts +6 -1
  348. package/src/runtime-detect.test.ts +30 -0
  349. package/src/runtime-detect.ts +36 -0
  350. package/src/runtime.ts +3 -3
  351. package/src/serialization.ts +4 -0
  352. package/src/types.ts +3 -0
  353. package/src/update-check.ts +114 -0
  354. package/src/weixin-download.test.ts +64 -0
  355. package/src/weread-private-api-regression.test.ts +150 -0
  356. package/src/yaml-schema.ts +20 -0
  357. package/tests/e2e/browser-auth.test.ts +13 -9
  358. package/tests/e2e/browser-public-extended.test.ts +1 -1
  359. package/tests/e2e/browser-public.test.ts +62 -4
  360. package/tests/e2e/helpers.ts +2 -1
  361. package/tests/e2e/public-commands.test.ts +37 -3
  362. package/tests/smoke/api-health.test.ts +1 -1
  363. package/vitest.config.ts +10 -0
  364. package/dist/clis/linux-do/category.yaml +0 -51
  365. package/dist/clis/linux-do/hot.yaml +0 -50
  366. package/dist/clis/linux-do/latest.yaml +0 -40
  367. package/src/clis/linux-do/category.yaml +0 -51
  368. package/src/clis/linux-do/hot.yaml +0 -50
  369. package/src/clis/linux-do/latest.yaml +0 -40
@@ -0,0 +1,200 @@
1
+ ---
2
+ description: How to turn a new Electron desktop app into an OpenCLI adapter
3
+ ---
4
+
5
+ # Add a New Electron App CLI
6
+
7
+ This guide is the **fast entry point** for turning a new Electron desktop application into an OpenCLI adapter.
8
+
9
+ If you want the full background and deeper SOP, read:
10
+ - [CLI-ifying Electron Applications](/advanced/electron)
11
+ - [Chrome DevTools Protocol](/advanced/cdp)
12
+ - [TypeScript Adapter Guide](/developer/ts-adapter)
13
+
14
+ ## When to use this guide
15
+
16
+ Use this workflow when the target app:
17
+ - is built with **Electron**, or at least exposes a working **Chrome DevTools Protocol (CDP)** endpoint
18
+ - can be launched with `--remote-debugging-port=<port>`
19
+ - should be automated through its real UI instead of a public HTTP API
20
+
21
+ If the app is **not** Electron and does **not** expose CDP, use the native desktop automation pattern instead. See [CLI-ifying Electron Applications](/advanced/electron#non-electron-pattern-applescript).
22
+
23
+ ## The shortest path
24
+
25
+ ### 1. Confirm the app is Electron
26
+
27
+ Typical macOS check:
28
+
29
+ ```bash
30
+ ls /Applications/AppName.app/Contents/Frameworks/Electron\ Framework.framework
31
+ ```
32
+
33
+ If Electron is present, the next step is usually to launch the app with a debugging port.
34
+
35
+ ### 2. Launch it with CDP enabled
36
+
37
+ ```bash
38
+ /Applications/AppName.app/Contents/MacOS/AppName --remote-debugging-port=9222
39
+ ```
40
+
41
+ Then point OpenCLI at that CDP endpoint:
42
+
43
+ ```bash
44
+ export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9222"
45
+ ```
46
+
47
+ ### 3. Start with the 5-command pattern
48
+
49
+ For a new Electron adapter, implement these commands first in `src/clis/<app>/`:
50
+
51
+ - `status.ts` — verify the app is reachable through CDP
52
+ - `dump.ts` — inspect DOM and snapshot structure before guessing selectors
53
+ - `read.ts` — extract the visible context you actually need
54
+ - `send.ts` — inject text and submit through the real editor
55
+ - `new.ts` — create a new session, tab, thread, or document
56
+
57
+ This is the standard baseline because it gives you:
58
+ - a connection check
59
+ - a reverse-engineering tool
60
+ - one read path
61
+ - one write path
62
+ - one session reset path
63
+
64
+ The full rationale and examples are in [CLI-ifying Electron Applications](/advanced/electron).
65
+
66
+ ## Recommended implementation workflow
67
+
68
+ ### Step 1: Build `status`
69
+
70
+ Goal: prove CDP connectivity before touching app-specific logic.
71
+
72
+ Typical checks:
73
+ - current URL
74
+ - document title
75
+ - app shell presence
76
+
77
+ If `status` is unstable, stop there and fix connectivity first.
78
+
79
+ ### Step 2: Build `dump`
80
+
81
+ Do **not** guess selectors from the rendered UI.
82
+
83
+ Dump:
84
+ - `document.body.innerHTML`
85
+ - accessibility snapshot
86
+ - any stable attributes such as `data-testid`, `role`, `aria-*`, framework-specific markers
87
+
88
+ Use the dump to identify real containers, buttons, composers, and conversation regions.
89
+
90
+ ### Step 3: Build `read`
91
+
92
+ Target only the app region that matters.
93
+
94
+ Good targets:
95
+ - message list
96
+ - editor history
97
+ - visible thread content
98
+ - selected document panel
99
+
100
+ Avoid dumping the entire page text into the final command output.
101
+
102
+ ### Step 4: Build `send`
103
+
104
+ Most Electron apps use React-style controlled editors, so direct `.value = ...` assignments are often ignored.
105
+
106
+ Prefer editor-aware input patterns such as:
107
+ - focus the editable region
108
+ - use `document.execCommand('insertText', false, text)` when applicable
109
+ - use real key presses like `Enter`, `Meta+Enter`, or app-specific shortcuts
110
+
111
+ ### Step 5: Build `new`
112
+
113
+ Many desktop apps rely on keyboard shortcuts for “new chat”, “new tab”, or “new note”.
114
+
115
+ Typical pattern:
116
+
117
+ ```ts
118
+ const isMac = process.platform === 'darwin';
119
+ await page.pressKey(isMac ? 'Meta+N' : 'Control+N');
120
+ await page.wait(1);
121
+ ```
122
+
123
+ ## Where to put files
124
+
125
+ For a TypeScript desktop adapter, the usual layout is:
126
+
127
+ ```text
128
+ src/clis/<app>/status.ts
129
+ src/clis/<app>/dump.ts
130
+ src/clis/<app>/read.ts
131
+ src/clis/<app>/send.ts
132
+ src/clis/<app>/new.ts
133
+ src/clis/<app>/utils.ts
134
+ ```
135
+
136
+ If the app grows beyond the baseline, add higher-level commands such as:
137
+ - `ask`
138
+ - `history`
139
+ - `model`
140
+ - `screenshot`
141
+ - `export`
142
+
143
+ ## What to document when you add a new app
144
+
145
+ When the adapter is ready, also add:
146
+
147
+ - an adapter doc under `docs/adapters/desktop/`
148
+ - command list and examples
149
+ - launch instructions with `--remote-debugging-port`
150
+ - any required environment variables
151
+ - platform-specific caveats
152
+
153
+ Examples to study:
154
+ - `docs/adapters/desktop/codex.md`
155
+ - `docs/adapters/desktop/chatwise.md`
156
+ - `docs/adapters/desktop/notion.md`
157
+ - `docs/adapters/desktop/discord.md`
158
+
159
+ ## Common failure modes
160
+
161
+ ### CDP endpoint exists, but commands are flaky
162
+
163
+ Usually one of these:
164
+ - the wrong window/tab is selected
165
+ - the app has not finished rendering
166
+ - selectors were guessed instead of discovered from `dump`
167
+ - the editor is controlled and ignores direct value assignment
168
+
169
+ ### The app is Chromium-based but not truly controllable
170
+
171
+ Some desktop apps embed Chromium but do not expose a usable CDP surface.
172
+ In that case, switch to the non-Electron desktop automation approach instead of forcing the Electron pattern.
173
+
174
+ ### You already have a browser workflow and wonder whether to reuse it
175
+
176
+ If the app exposes a normal web URL and the browser flow is enough, a browser adapter is usually simpler.
177
+ Use an Electron adapter only when the desktop app is the real integration surface.
178
+
179
+ ## Recommended reading order
180
+
181
+ If you are starting from zero:
182
+
183
+ 1. This page
184
+ 2. [CLI-ifying Electron Applications](/advanced/electron)
185
+ 3. [Chrome DevTools Protocol](/advanced/cdp)
186
+ 4. [TypeScript Adapter Guide](/developer/ts-adapter)
187
+ 5. One concrete desktop adapter doc under `docs/adapters/desktop/`
188
+
189
+ ## Practical rule
190
+
191
+ Do not start with a large feature surface.
192
+
193
+ Start with:
194
+ - `status`
195
+ - `dump`
196
+ - `read`
197
+ - `send`
198
+ - `new`
199
+
200
+ Once those are stable, extend outward.
@@ -55,3 +55,4 @@ opencli bilibili hot -v # Verbose: show pipeline debug
55
55
  - [Plugins — extend with community adapters](/guide/plugins)
56
56
  - [All available adapters](/adapters/)
57
57
  - [For developers / AI agents](/developer/contributing)
58
+ - [Add a new Electron app CLI](/guide/electron-app-cli)
@@ -31,12 +31,109 @@ Plugins live in `~/.opencli/plugins/<name>/`. Each subdirectory is scanned at st
31
31
  ### Supported Source Formats
32
32
 
33
33
  ```bash
34
+ # GitHub shorthand
34
35
  opencli plugin install github:user/repo
36
+ opencli plugin install github:user/repo/subplugin # install specific sub-plugin from monorepo
35
37
  opencli plugin install https://github.com/user/repo
38
+
39
+ # Any git-cloneable URL
40
+ opencli plugin install https://gitlab.example.com/team/repo.git
41
+ opencli plugin install ssh://git@gitlab.example.com/team/repo.git
42
+ opencli plugin install git@gitlab.example.com:team/repo.git
43
+
44
+ # Local plugin (for development)
45
+ opencli plugin install file:///path/to/plugin
46
+ opencli plugin install /path/to/plugin
36
47
  ```
37
48
 
38
49
  The repo name prefix `opencli-plugin-` is automatically stripped for the local directory name. For example, `opencli-plugin-hot-digest` becomes `hot-digest`.
39
50
 
51
+ ## Plugin Manifest (`opencli-plugin.json`)
52
+
53
+ Plugins can include an `opencli-plugin.json` manifest file at the repo root to declare metadata:
54
+
55
+ ```json
56
+ {
57
+ "name": "my-plugin",
58
+ "version": "1.0.0",
59
+ "opencli": ">=1.0.0",
60
+ "description": "My awesome plugin"
61
+ }
62
+ ```
63
+
64
+ | Field | Description |
65
+ |-------|-------------|
66
+ | `name` | Plugin name (overrides repo-derived name) |
67
+ | `version` | Semantic version |
68
+ | `opencli` | Required opencli version range (e.g. `>=1.0.0`, `^1.2.0`) |
69
+ | `description` | Human-readable description |
70
+ | `plugins` | Monorepo sub-plugin declarations (see below) |
71
+
72
+ The manifest is optional — plugins without one continue to work exactly as before.
73
+
74
+ ## Monorepo Plugins
75
+
76
+ A single repository can contain multiple plugins by declaring a `plugins` field in `opencli-plugin.json`:
77
+
78
+ ```json
79
+ {
80
+ "version": "1.0.0",
81
+ "opencli": ">=1.0.0",
82
+ "description": "My plugin collection",
83
+ "plugins": {
84
+ "polymarket": {
85
+ "path": "packages/polymarket",
86
+ "description": "Prediction market analysis",
87
+ "version": "1.2.0"
88
+ },
89
+ "defi": {
90
+ "path": "packages/defi",
91
+ "description": "DeFi protocol data",
92
+ "version": "0.8.0",
93
+ "opencli": ">=1.2.0"
94
+ },
95
+ "experimental": {
96
+ "path": "packages/experimental",
97
+ "disabled": true
98
+ }
99
+ }
100
+ }
101
+ ```
102
+
103
+ ### Installing
104
+
105
+ ```bash
106
+ # Install ALL enabled sub-plugins from a monorepo
107
+ opencli plugin install github:user/opencli-plugins
108
+
109
+ # Install a SPECIFIC sub-plugin
110
+ opencli plugin install github:user/opencli-plugins/polymarket
111
+ ```
112
+
113
+ ### How It Works
114
+
115
+ - The monorepo is cloned once to `~/.opencli/monorepos/<repo>/`
116
+ - Each sub-plugin gets a symlink in `~/.opencli/plugins/<name>/` pointing to its subdirectory
117
+ - Command discovery works transparently — symlinks are scanned just like regular directories
118
+ - Disabled sub-plugins (with `"disabled": true`) are skipped during install
119
+ - Sub-plugins can specify their own `opencli` compatibility range
120
+
121
+ ### Updating
122
+
123
+ Updating any sub-plugin from a monorepo pulls the entire repo and refreshes all sub-plugins:
124
+
125
+ ```bash
126
+ opencli plugin update polymarket # updates the monorepo, refreshes all
127
+ ```
128
+
129
+ ### Uninstalling
130
+
131
+ ```bash
132
+ opencli plugin uninstall polymarket # removes just this sub-plugin's symlink
133
+ ```
134
+
135
+ When the last sub-plugin from a monorepo is uninstalled, the monorepo clone is automatically cleaned up.
136
+
40
137
  ## Version Tracking
41
138
 
42
139
  OpenCLI records installed plugin versions in `~/.opencli/plugins.lock.json`. Each entry stores the plugin source, current git commit hash, install time, and last update time. `opencli plugin list` shows the short commit hash when version metadata is available.
@@ -0,0 +1,188 @@
1
+ # 给新 Electron 应用生成 CLI
2
+
3
+ 这篇文档是把一个新的 Electron 桌面应用接入 OpenCLI 的**中文入口指南**。
4
+
5
+ 如果你需要更完整的背景和标准流程,继续看:
6
+ - [Chrome DevTools Protocol(中文)](/zh/advanced/cdp)
7
+ - [CLI-ifying Electron Applications(英文深度版)](/advanced/electron)
8
+ - [TypeScript 适配器开发指南(英文)](/developer/ts-adapter)
9
+
10
+ ## 这篇文档适合什么场景
11
+
12
+ 当目标应用满足下面条件时,用这套流程:
13
+ - 应用是 **Electron**,或者至少能暴露可用的 **CDP(Chrome DevTools Protocol)** 端口
14
+ - 可以通过 `--remote-debugging-port=<port>` 启动
15
+ - 你希望控制的是桌面应用本身,而不是它背后的公开 HTTP API
16
+
17
+ 如果应用**不是** Electron,或者不暴露 CDP,就不要硬套这套方案。那种情况应改用原生桌面自动化方案。可参考 [英文版说明](/advanced/electron#non-electron-pattern-applescript)。
18
+
19
+ ## 最短落地路径
20
+
21
+ ### 1. 先确认它是不是 Electron
22
+
23
+ macOS 下常见检查方式:
24
+
25
+ ```bash
26
+ ls /Applications/AppName.app/Contents/Frameworks/Electron\ Framework.framework
27
+ ```
28
+
29
+ 如果存在,通常就可以继续尝试 CDP。
30
+
31
+ ### 2. 带 CDP 端口启动应用
32
+
33
+ ```bash
34
+ /Applications/AppName.app/Contents/MacOS/AppName --remote-debugging-port=9222
35
+ ```
36
+
37
+ 然后把 OpenCLI 指到这个端口:
38
+
39
+ ```bash
40
+ export OPENCLI_CDP_ENDPOINT="http://127.0.0.1:9222"
41
+ ```
42
+
43
+ ### 3. 先做 5 个基础命令
44
+
45
+ 建议一个新 Electron 适配器先实现这 5 个命令:
46
+
47
+ - `status.ts` —— 确认 CDP 连通
48
+ - `dump.ts` —— 导出 DOM / snapshot,先做逆向再写逻辑
49
+ - `read.ts` —— 读取当前上下文
50
+ - `send.ts` —— 往真实编辑器里输入并发送
51
+ - `new.ts` —— 新建会话 / 标签页 / 文档
52
+
53
+ 这是最稳妥的基线,因为它先把“能连上、能看见、能读、能写、能重置状态”这 5 件核心事情打通了。
54
+
55
+ ## 推荐开发顺序
56
+
57
+ ### 第一步:先做 `status`
58
+
59
+ 目标不是功能,而是先证明:
60
+ - CDP 真的连上了
61
+ - 你连到的是对的窗口/标签页
62
+ - 应用当前页面确实可读
63
+
64
+ 如果 `status` 都不稳定,先不要继续往下做。
65
+
66
+ ### 第二步:做 `dump`
67
+
68
+ **不要猜 selector。**
69
+
70
+ 先把这些导出来:
71
+ - `document.body.innerHTML`
72
+ - accessibility snapshot
73
+ - 稳定属性:`data-testid`、`role`、`aria-*` 等
74
+
75
+ 然后再决定:
76
+ - 消息列表在哪
77
+ - 输入框在哪
78
+ - 按钮在哪
79
+ - 当前会话容器在哪
80
+
81
+ ### 第三步:做 `read`
82
+
83
+ 只读真正需要的区域,不要把整个页面文本都塞出来。
84
+
85
+ 常见目标:
86
+ - 对话消息区
87
+ - 当前线程内容
88
+ - 当前编辑器历史
89
+ - 当前文档主区域
90
+
91
+ ### 第四步:做 `send`
92
+
93
+ 很多 Electron 应用的输入框是 React 控制组件,直接改 `.value` 往往没用。
94
+
95
+ 更稳妥的方式通常是:
96
+ - 先 focus 到可编辑区域
97
+ - 能用时优先 `document.execCommand('insertText', false, text)`
98
+ - 最后用真实按键提交,比如 `Enter`、`Meta+Enter`
99
+
100
+ ### 第五步:做 `new`
101
+
102
+ 很多桌面应用的新建动作其实更适合走快捷键,而不是点按钮。
103
+
104
+ 典型模式:
105
+
106
+ ```ts
107
+ const isMac = process.platform === 'darwin';
108
+ await page.pressKey(isMac ? 'Meta+N' : 'Control+N');
109
+ await page.wait(1);
110
+ ```
111
+
112
+ ## 文件一般怎么放
113
+
114
+ 一个 TypeScript 桌面适配器,通常结构是:
115
+
116
+ ```text
117
+ src/clis/<app>/status.ts
118
+ src/clis/<app>/dump.ts
119
+ src/clis/<app>/read.ts
120
+ src/clis/<app>/send.ts
121
+ src/clis/<app>/new.ts
122
+ src/clis/<app>/utils.ts
123
+ ```
124
+
125
+ 当基础能力稳定后,再继续加:
126
+ - `ask`
127
+ - `history`
128
+ - `model`
129
+ - `screenshot`
130
+ - `export`
131
+
132
+ ## 加完适配器后,还应该补什么文档
133
+
134
+ 至少补这几项:
135
+ - `docs/adapters/desktop/` 下的适配器说明页
136
+ - 命令列表和示例
137
+ - 如何带 `--remote-debugging-port` 启动
138
+ - 需要哪些环境变量
139
+ - 平台限制和注意事项
140
+
141
+ 可以参考这些现成文档:
142
+ - `docs/adapters/desktop/codex.md`
143
+ - `docs/adapters/desktop/chatwise.md`
144
+ - `docs/adapters/desktop/notion.md`
145
+ - `docs/adapters/desktop/discord.md`
146
+
147
+ ## 常见问题
148
+
149
+ ### CDP 能连,但命令不稳定
150
+
151
+ 常见原因:
152
+ - 连错窗口或标签页
153
+ - 页面还没渲染完
154
+ - selector 是猜的,不是从 `dump` 里找出来的
155
+ - 输入框是受控组件,直接赋值不生效
156
+
157
+ ### 应用看起来像 Chromium,但就是不好控
158
+
159
+ 有些桌面应用虽然嵌了 Chromium,但并不真正暴露可用的 CDP 接口。
160
+ 这种情况不要强行走 Electron 方案,应该换到非 Electron 的桌面自动化方案。
161
+
162
+ ### 这个应用其实也有网页版本,还要不要做 Electron 适配器
163
+
164
+ 如果网页版本已经足够稳定,浏览器适配器通常更简单。
165
+ 只有当**桌面应用才是真正的集成面**时,再优先做 Electron 适配器。
166
+
167
+ ## 推荐阅读顺序
168
+
169
+ 如果你从零开始:
170
+
171
+ 1. 先看这篇
172
+ 2. 再看 [CLI-ifying Electron Applications(英文深度版)](/advanced/electron)
173
+ 3. 再看 [Chrome DevTools Protocol(中文)](/zh/advanced/cdp)
174
+ 4. 再看 [TypeScript Adapter Guide(英文)](/developer/ts-adapter)
175
+ 5. 最后找一个现成桌面适配器文档照着做
176
+
177
+ ## 最后一个实践建议
178
+
179
+ 不要一上来就做很大的命令面。
180
+
181
+ 先把下面 5 个做稳:
182
+ - `status`
183
+ - `dump`
184
+ - `read`
185
+ - `send`
186
+ - `new`
187
+
188
+ 这 5 个稳定了,再往外扩,成本最低,返工也最少。
@@ -38,3 +38,4 @@ opencli bilibili hot -f csv # CSV
38
38
  - [Browser Bridge 设置](/zh/guide/browser-bridge)
39
39
  - [所有适配器](/zh/adapters/)
40
40
  - [开发者指南](/zh/developer/contributing)
41
+ - [给新 Electron 应用生成 CLI](/zh/guide/electron-app-cli)
@@ -32,11 +32,76 @@ Plugins 存放在 `~/.opencli/plugins/<name>/`。每个子目录都会在启动
32
32
 
33
33
  ```bash
34
34
  opencli plugin install github:user/repo
35
+ opencli plugin install github:user/repo/subplugin # 安装 monorepo 中的指定子插件
35
36
  opencli plugin install https://github.com/user/repo
36
37
  ```
37
38
 
38
39
  如果仓库名带 `opencli-plugin-` 前缀,本地目录会自动去掉这个前缀。例如 `opencli-plugin-hot-digest` 会变成 `hot-digest`。
39
40
 
41
+ ## 插件清单 (`opencli-plugin.json`)
42
+
43
+ 插件可以在仓库根目录放置 `opencli-plugin.json` 来声明元数据:
44
+
45
+ ```json
46
+ {
47
+ "name": "my-plugin",
48
+ "version": "1.0.0",
49
+ "opencli": ">=1.0.0",
50
+ "description": "我的插件"
51
+ }
52
+ ```
53
+
54
+ | 字段 | 说明 |
55
+ |------|------|
56
+ | `name` | 插件名称(覆盖从仓库名推导的名称) |
57
+ | `version` | 语义化版本 |
58
+ | `opencli` | 所需的 opencli 版本范围(如 `>=1.0.0`、`^1.2.0`) |
59
+ | `description` | 描述 |
60
+ | `plugins` | Monorepo 子插件声明(见下文) |
61
+
62
+ 清单文件是可选的——没有它的插件依然可以正常工作。
63
+
64
+ ## Monorepo 插件
65
+
66
+ 一个仓库可以通过在 `opencli-plugin.json` 中声明 `plugins` 字段来包含多个插件:
67
+
68
+ ```json
69
+ {
70
+ "version": "1.0.0",
71
+ "opencli": ">=1.0.0",
72
+ "description": "我的插件合集",
73
+ "plugins": {
74
+ "polymarket": {
75
+ "path": "packages/polymarket",
76
+ "description": "预测市场分析",
77
+ "version": "1.2.0"
78
+ },
79
+ "defi": {
80
+ "path": "packages/defi",
81
+ "description": "DeFi 协议数据",
82
+ "version": "0.8.0"
83
+ },
84
+ "experimental": {
85
+ "path": "packages/experimental",
86
+ "disabled": true
87
+ }
88
+ }
89
+ }
90
+ ```
91
+
92
+ ```bash
93
+ # 安装 monorepo 中的全部子插件
94
+ opencli plugin install github:user/opencli-plugins
95
+
96
+ # 安装指定子插件
97
+ opencli plugin install github:user/opencli-plugins/polymarket
98
+ ```
99
+
100
+ - Monorepo 只 clone 一次到 `~/.opencli/monorepos/<repo>/`
101
+ - 每个子插件通过 symlink 出现在 `~/.opencli/plugins/<name>/`
102
+ - 更新任何子插件会拉取整个 monorepo 并刷新所有子插件
103
+ - 卸载最后一个子插件时,monorepo 目录会被自动清理
104
+
40
105
  ## 版本追踪
41
106
 
42
107
  OpenCLI 会把已安装 plugin 的版本记录到 `~/.opencli/plugins.lock.json`。每条记录会保存 plugin source、当前 git commit hash、安装时间,以及最近一次更新时间。只要有这份元数据,`opencli plugin list` 就会显示对应的短 commit hash。
@@ -6,6 +6,7 @@
6
6
  "scripts": {
7
7
  "dev": "vite build --watch",
8
8
  "build": "vite build",
9
+ "package:release": "node scripts/package-release.mjs",
9
10
  "typecheck": "tsc --noEmit"
10
11
  },
11
12
  "devDependencies": {