@jackwener/opencli 1.7.10 → 1.7.12

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 (740) hide show
  1. package/README.md +3 -3
  2. package/README.zh-CN.md +5 -4
  3. package/cli-manifest.json +1443 -24
  4. package/clis/1688/assets.js +1 -0
  5. package/clis/1688/download.js +1 -0
  6. package/clis/1688/item.js +1 -0
  7. package/clis/1688/search.js +2 -1
  8. package/clis/1688/store.js +1 -0
  9. package/clis/36kr/article.js +1 -0
  10. package/clis/36kr/hot.js +1 -0
  11. package/clis/36kr/news.js +1 -0
  12. package/clis/36kr/search.js +1 -0
  13. package/clis/51job/company.js +1 -0
  14. package/clis/51job/detail.js +1 -0
  15. package/clis/51job/hot.js +1 -0
  16. package/clis/51job/search.js +1 -0
  17. package/clis/amazon/bestsellers.js +1 -0
  18. package/clis/amazon/discussion.js +1 -0
  19. package/clis/amazon/movers-shakers.js +1 -0
  20. package/clis/amazon/new-releases.js +1 -0
  21. package/clis/amazon/offer.js +1 -0
  22. package/clis/amazon/product.js +1 -0
  23. package/clis/amazon/rankings.js +1 -0
  24. package/clis/amazon/search.js +1 -0
  25. package/clis/antigravity/dump.js +1 -0
  26. package/clis/antigravity/extract-code.js +1 -0
  27. package/clis/antigravity/model.js +1 -0
  28. package/clis/antigravity/new.js +1 -0
  29. package/clis/antigravity/read.js +1 -0
  30. package/clis/antigravity/send.js +1 -0
  31. package/clis/antigravity/status.js +1 -0
  32. package/clis/antigravity/watch.js +1 -0
  33. package/clis/apple-podcasts/episodes.js +1 -0
  34. package/clis/apple-podcasts/search.js +1 -0
  35. package/clis/apple-podcasts/top.js +1 -0
  36. package/clis/arxiv/arxiv.test.js +112 -0
  37. package/clis/arxiv/paper.js +4 -3
  38. package/clis/arxiv/recent.js +33 -0
  39. package/clis/arxiv/search.js +19 -7
  40. package/clis/arxiv/utils.js +68 -5
  41. package/clis/baidu-scholar/search.js +1 -0
  42. package/clis/band/bands.js +1 -0
  43. package/clis/band/mentions.js +1 -0
  44. package/clis/band/post.js +1 -0
  45. package/clis/band/posts.js +1 -0
  46. package/clis/barchart/flow.js +1 -0
  47. package/clis/barchart/greeks.js +1 -0
  48. package/clis/barchart/options.js +1 -0
  49. package/clis/barchart/quote.js +1 -0
  50. package/clis/bbc/news.js +1 -0
  51. package/clis/bilibili/comments.js +1 -0
  52. package/clis/bilibili/download.js +1 -0
  53. package/clis/bilibili/dynamic.js +1 -0
  54. package/clis/bilibili/favorite.js +1 -0
  55. package/clis/bilibili/feed.js +2 -0
  56. package/clis/bilibili/following.js +1 -0
  57. package/clis/bilibili/history.js +1 -0
  58. package/clis/bilibili/hot.js +6 -1
  59. package/clis/bilibili/hot.test.js +17 -0
  60. package/clis/bilibili/me.js +1 -1
  61. package/clis/bilibili/ranking.js +1 -0
  62. package/clis/bilibili/search.js +1 -1
  63. package/clis/bilibili/subtitle.js +1 -0
  64. package/clis/bilibili/user-videos.js +1 -0
  65. package/clis/bilibili/video.js +1 -0
  66. package/clis/binance/asks.js +1 -0
  67. package/clis/binance/depth.js +1 -0
  68. package/clis/binance/gainers.js +1 -0
  69. package/clis/binance/klines.js +1 -0
  70. package/clis/binance/losers.js +1 -0
  71. package/clis/binance/pairs.js +1 -0
  72. package/clis/binance/price.js +1 -0
  73. package/clis/binance/prices.js +1 -0
  74. package/clis/binance/ticker.js +1 -0
  75. package/clis/binance/top.js +1 -0
  76. package/clis/binance/trades.js +1 -0
  77. package/clis/bloomberg/businessweek.js +1 -0
  78. package/clis/bloomberg/economics.js +1 -0
  79. package/clis/bloomberg/feeds.js +1 -0
  80. package/clis/bloomberg/industries.js +1 -0
  81. package/clis/bloomberg/main.js +1 -0
  82. package/clis/bloomberg/markets.js +1 -0
  83. package/clis/bloomberg/news.js +1 -0
  84. package/clis/bloomberg/opinions.js +1 -0
  85. package/clis/bloomberg/politics.js +1 -0
  86. package/clis/bloomberg/tech.js +1 -0
  87. package/clis/bluesky/feeds.js +1 -0
  88. package/clis/bluesky/followers.js +1 -0
  89. package/clis/bluesky/following.js +1 -0
  90. package/clis/bluesky/profile.js +1 -0
  91. package/clis/bluesky/search.js +1 -0
  92. package/clis/bluesky/starter-packs.js +1 -0
  93. package/clis/bluesky/thread.js +1 -0
  94. package/clis/bluesky/trending.js +1 -0
  95. package/clis/bluesky/user.js +3 -1
  96. package/clis/boss/batchgreet.js +1 -0
  97. package/clis/boss/chatlist.js +1 -0
  98. package/clis/boss/chatmsg.js +1 -0
  99. package/clis/boss/detail.js +1 -0
  100. package/clis/boss/exchange.js +1 -0
  101. package/clis/boss/greet.js +1 -0
  102. package/clis/boss/invite.js +1 -0
  103. package/clis/boss/joblist.js +1 -0
  104. package/clis/boss/mark.js +1 -0
  105. package/clis/boss/recommend.js +1 -0
  106. package/clis/boss/resume.js +1 -0
  107. package/clis/boss/search.js +1 -0
  108. package/clis/boss/send.js +1 -0
  109. package/clis/boss/stats.js +1 -0
  110. package/clis/chaoxing/assignments.js +1 -0
  111. package/clis/chaoxing/exams.js +1 -0
  112. package/clis/chatgpt/image.js +1 -0
  113. package/clis/chatgpt-app/ask.js +1 -0
  114. package/clis/chatgpt-app/model.js +1 -0
  115. package/clis/chatgpt-app/new.js +1 -0
  116. package/clis/chatgpt-app/read.js +1 -0
  117. package/clis/chatgpt-app/send.js +1 -0
  118. package/clis/chatgpt-app/status.js +1 -0
  119. package/clis/chatwise/ask.js +1 -0
  120. package/clis/chatwise/export.js +1 -0
  121. package/clis/chatwise/history.js +1 -0
  122. package/clis/chatwise/model.js +1 -0
  123. package/clis/chatwise/read.js +1 -0
  124. package/clis/chatwise/send.js +1 -0
  125. package/clis/claude/ask.js +1 -0
  126. package/clis/claude/detail.js +1 -0
  127. package/clis/claude/history.js +1 -0
  128. package/clis/claude/new.js +1 -0
  129. package/clis/claude/read.js +1 -0
  130. package/clis/claude/send.js +1 -0
  131. package/clis/claude/status.js +1 -0
  132. package/clis/cnki/search.js +1 -0
  133. package/clis/codex/ask.js +1 -0
  134. package/clis/codex/export.js +1 -0
  135. package/clis/codex/extract-diff.js +1 -0
  136. package/clis/codex/history.js +1 -0
  137. package/clis/codex/model.js +1 -0
  138. package/clis/codex/read.js +1 -0
  139. package/clis/codex/send.js +1 -0
  140. package/clis/coupang/add-to-cart.js +1 -0
  141. package/clis/coupang/search.js +1 -0
  142. package/clis/ctrip/search.js +1 -0
  143. package/clis/cursor/ask.js +1 -0
  144. package/clis/cursor/composer.js +1 -0
  145. package/clis/cursor/export.js +1 -0
  146. package/clis/cursor/extract-code.js +1 -0
  147. package/clis/cursor/history.js +1 -0
  148. package/clis/cursor/model.js +1 -0
  149. package/clis/cursor/read.js +1 -0
  150. package/clis/cursor/send.js +1 -0
  151. package/clis/dblp/dblp.test.js +397 -0
  152. package/clis/dblp/paper.js +40 -0
  153. package/clis/dblp/search.js +45 -0
  154. package/clis/dblp/utils.js +290 -0
  155. package/clis/deepseek/ask.js +1 -0
  156. package/clis/deepseek/history.js +1 -0
  157. package/clis/deepseek/new.js +1 -0
  158. package/clis/deepseek/read.js +1 -0
  159. package/clis/deepseek/status.js +1 -0
  160. package/clis/devto/devto.test.js +236 -0
  161. package/clis/devto/read.js +103 -0
  162. package/clis/devto/tag.js +5 -1
  163. package/clis/devto/top.js +5 -1
  164. package/clis/devto/user.js +5 -1
  165. package/clis/dianping/__fixtures__/search.html +168 -0
  166. package/clis/dianping/__fixtures__/shop.html +6 -0
  167. package/clis/dianping/dianping.test.js +424 -0
  168. package/clis/dianping/search.js +154 -0
  169. package/clis/dianping/shop.js +173 -0
  170. package/clis/dianping/utils.js +157 -0
  171. package/clis/dictionary/examples.js +1 -0
  172. package/clis/dictionary/search.js +1 -0
  173. package/clis/dictionary/synonyms.js +1 -0
  174. package/clis/discord-app/channels.js +1 -0
  175. package/clis/discord-app/delete.js +1 -0
  176. package/clis/discord-app/members.js +1 -0
  177. package/clis/discord-app/read.js +1 -0
  178. package/clis/discord-app/search.js +1 -0
  179. package/clis/discord-app/send.js +1 -0
  180. package/clis/discord-app/servers.js +1 -0
  181. package/clis/discord-app/status.js +1 -0
  182. package/clis/douban/book-hot.js +1 -0
  183. package/clis/douban/download.js +1 -0
  184. package/clis/douban/marks.js +1 -0
  185. package/clis/douban/movie-hot.js +2 -1
  186. package/clis/douban/movie-hot.test.js +14 -0
  187. package/clis/douban/photos.js +2 -1
  188. package/clis/douban/reviews.js +1 -0
  189. package/clis/douban/search.js +1 -0
  190. package/clis/douban/subject.js +1 -0
  191. package/clis/douban/top250.js +1 -0
  192. package/clis/douban/utils.js +11 -13
  193. package/clis/douban/utils.test.js +79 -0
  194. package/clis/doubao/ask.js +1 -0
  195. package/clis/doubao/detail.js +1 -0
  196. package/clis/doubao/history.js +1 -0
  197. package/clis/doubao/meeting-summary.js +1 -0
  198. package/clis/doubao/meeting-transcript.js +1 -0
  199. package/clis/doubao/new.js +1 -0
  200. package/clis/doubao/read.js +1 -0
  201. package/clis/doubao/send.js +1 -0
  202. package/clis/doubao/status.js +1 -0
  203. package/clis/doubao-app/ask.js +1 -0
  204. package/clis/doubao-app/dump.js +1 -0
  205. package/clis/doubao-app/new.js +1 -0
  206. package/clis/doubao-app/read.js +1 -0
  207. package/clis/doubao-app/screenshot.js +1 -0
  208. package/clis/doubao-app/send.js +1 -0
  209. package/clis/doubao-app/status.js +1 -0
  210. package/clis/douyin/activities.js +1 -0
  211. package/clis/douyin/collections.js +1 -0
  212. package/clis/douyin/delete.js +1 -0
  213. package/clis/douyin/draft.js +1 -0
  214. package/clis/douyin/drafts.js +1 -0
  215. package/clis/douyin/hashtag.js +1 -0
  216. package/clis/douyin/location.js +1 -0
  217. package/clis/douyin/profile.js +1 -0
  218. package/clis/douyin/publish.js +1 -0
  219. package/clis/douyin/stats.js +1 -0
  220. package/clis/douyin/update.js +1 -0
  221. package/clis/douyin/user-videos.js +1 -0
  222. package/clis/douyin/videos.js +1 -0
  223. package/clis/eastmoney/announcement.js +1 -0
  224. package/clis/eastmoney/convertible.js +1 -0
  225. package/clis/eastmoney/etf.js +1 -0
  226. package/clis/eastmoney/holders.js +1 -0
  227. package/clis/eastmoney/hot-rank.js +1 -0
  228. package/clis/eastmoney/index-board.js +1 -0
  229. package/clis/eastmoney/kline.js +1 -0
  230. package/clis/eastmoney/kuaixun.js +1 -0
  231. package/clis/eastmoney/longhu.js +1 -0
  232. package/clis/eastmoney/money-flow.js +1 -0
  233. package/clis/eastmoney/northbound.js +1 -0
  234. package/clis/eastmoney/quote.js +1 -0
  235. package/clis/eastmoney/rank.js +1 -0
  236. package/clis/eastmoney/sectors.js +1 -0
  237. package/clis/facebook/add-friend.js +1 -0
  238. package/clis/facebook/events.js +1 -0
  239. package/clis/facebook/feed.js +1 -0
  240. package/clis/facebook/friends.js +1 -0
  241. package/clis/facebook/groups.js +1 -0
  242. package/clis/facebook/join-group.js +1 -0
  243. package/clis/facebook/marketplace-inbox.js +1 -0
  244. package/clis/facebook/marketplace-listings.js +1 -0
  245. package/clis/facebook/memories.js +1 -0
  246. package/clis/facebook/notifications.js +1 -0
  247. package/clis/facebook/profile.js +1 -0
  248. package/clis/facebook/search.js +1 -0
  249. package/clis/gemini/ask.js +1 -0
  250. package/clis/gemini/deep-research-result.js +1 -0
  251. package/clis/gemini/deep-research.js +1 -0
  252. package/clis/gemini/image.js +1 -0
  253. package/clis/gemini/new.js +1 -0
  254. package/clis/gitee/search.js +1 -0
  255. package/clis/gitee/trending.js +1 -0
  256. package/clis/gitee/user.js +1 -0
  257. package/clis/google/news.js +1 -0
  258. package/clis/google/search.js +1 -0
  259. package/clis/google/suggest.js +1 -0
  260. package/clis/google/trends.js +1 -0
  261. package/clis/google-scholar/cite.js +1 -0
  262. package/clis/google-scholar/profile.js +1 -0
  263. package/clis/google-scholar/search.js +1 -0
  264. package/clis/gov-law/recent.js +1 -0
  265. package/clis/gov-law/search.js +1 -0
  266. package/clis/gov-policy/recent.js +1 -0
  267. package/clis/gov-policy/search.js +1 -0
  268. package/clis/grok/ask.js +1 -0
  269. package/clis/grok/image.ts +1 -0
  270. package/clis/hackernews/ask.js +3 -1
  271. package/clis/hackernews/best.js +3 -1
  272. package/clis/hackernews/hackernews.test.js +132 -0
  273. package/clis/hackernews/jobs.js +3 -1
  274. package/clis/hackernews/new.js +3 -1
  275. package/clis/hackernews/read.js +188 -0
  276. package/clis/hackernews/search.js +3 -1
  277. package/clis/hackernews/show.js +3 -1
  278. package/clis/hackernews/top.js +3 -1
  279. package/clis/hackernews/user.js +1 -0
  280. package/clis/hf/top.js +1 -0
  281. package/clis/hupu/detail.js +1 -0
  282. package/clis/hupu/hot.js +3 -1
  283. package/clis/hupu/like.js +1 -0
  284. package/clis/hupu/mentions.js +2 -1
  285. package/clis/hupu/reply.js +1 -0
  286. package/clis/hupu/search.js +3 -1
  287. package/clis/hupu/unlike.js +1 -0
  288. package/clis/imdb/person.js +1 -0
  289. package/clis/imdb/reviews.js +1 -0
  290. package/clis/imdb/search.js +1 -0
  291. package/clis/imdb/title.js +1 -0
  292. package/clis/imdb/top.js +1 -0
  293. package/clis/imdb/trending.js +1 -0
  294. package/clis/indeed/indeed.test.js +375 -0
  295. package/clis/indeed/job.js +86 -0
  296. package/clis/indeed/search.js +110 -0
  297. package/clis/indeed/utils.js +152 -0
  298. package/clis/instagram/collection-create.js +1 -0
  299. package/clis/instagram/collection-delete.js +92 -0
  300. package/clis/instagram/comment.js +1 -0
  301. package/clis/instagram/download.js +1 -0
  302. package/clis/instagram/explore.js +1 -0
  303. package/clis/instagram/follow.js +1 -0
  304. package/clis/instagram/followers.js +1 -0
  305. package/clis/instagram/following.js +1 -0
  306. package/clis/instagram/like.js +1 -0
  307. package/clis/instagram/note.js +1 -0
  308. package/clis/instagram/post.js +1 -0
  309. package/clis/instagram/profile.js +1 -0
  310. package/clis/instagram/reel.js +1 -0
  311. package/clis/instagram/save.js +1 -0
  312. package/clis/instagram/saved.js +1 -0
  313. package/clis/instagram/search.js +1 -0
  314. package/clis/instagram/story.js +1 -0
  315. package/clis/instagram/unfollow.js +1 -0
  316. package/clis/instagram/unlike.js +1 -0
  317. package/clis/instagram/unsave.js +1 -0
  318. package/clis/instagram/user.js +1 -0
  319. package/clis/jd/add-cart.js +1 -0
  320. package/clis/jd/cart.js +1 -0
  321. package/clis/jd/detail.js +1 -0
  322. package/clis/jd/item.js +1 -0
  323. package/clis/jd/reviews.js +1 -0
  324. package/clis/jd/search.js +1 -0
  325. package/clis/jianyu/detail.js +1 -0
  326. package/clis/jianyu/search.js +1 -0
  327. package/clis/jike/comment.js +1 -0
  328. package/clis/jike/create.js +1 -0
  329. package/clis/jike/feed.js +3 -1
  330. package/clis/jike/like.js +1 -0
  331. package/clis/jike/notifications.js +1 -0
  332. package/clis/jike/post.js +1 -0
  333. package/clis/jike/repost.js +1 -0
  334. package/clis/jike/search.js +3 -1
  335. package/clis/jike/topic.js +1 -0
  336. package/clis/jike/user.js +3 -1
  337. package/clis/jimeng/generate.js +1 -0
  338. package/clis/jimeng/history.js +1 -0
  339. package/clis/jimeng/new.js +1 -0
  340. package/clis/jimeng/workspaces.js +1 -0
  341. package/clis/ke/chengjiao.js +1 -0
  342. package/clis/ke/ershoufang.js +1 -0
  343. package/clis/ke/xiaoqu.js +1 -0
  344. package/clis/ke/zufang.js +1 -0
  345. package/clis/lesswrong/comments.js +1 -0
  346. package/clis/lesswrong/curated.js +1 -0
  347. package/clis/lesswrong/frontpage.js +1 -0
  348. package/clis/lesswrong/new.js +1 -0
  349. package/clis/lesswrong/read.js +1 -0
  350. package/clis/lesswrong/sequences.js +1 -0
  351. package/clis/lesswrong/shortform.js +1 -0
  352. package/clis/lesswrong/tag.js +1 -0
  353. package/clis/lesswrong/tags.js +1 -0
  354. package/clis/lesswrong/top-month.js +1 -0
  355. package/clis/lesswrong/top-week.js +1 -0
  356. package/clis/lesswrong/top-year.js +1 -0
  357. package/clis/lesswrong/top.js +1 -0
  358. package/clis/lesswrong/user-posts.js +1 -0
  359. package/clis/lesswrong/user.js +1 -0
  360. package/clis/linkedin/search.js +1 -0
  361. package/clis/linkedin/timeline.js +1 -0
  362. package/clis/linux-do/categories.js +1 -0
  363. package/clis/linux-do/category.js +1 -0
  364. package/clis/linux-do/feed.js +1 -0
  365. package/clis/linux-do/hot.js +1 -0
  366. package/clis/linux-do/latest.js +1 -0
  367. package/clis/linux-do/search.js +1 -0
  368. package/clis/linux-do/tags.js +2 -1
  369. package/clis/linux-do/topic-content.js +1 -0
  370. package/clis/linux-do/topic.js +1 -0
  371. package/clis/linux-do/user-posts.js +1 -0
  372. package/clis/linux-do/user-topics.js +1 -0
  373. package/clis/lobsters/active.js +4 -1
  374. package/clis/lobsters/hot.js +4 -1
  375. package/clis/lobsters/lobsters.test.js +169 -0
  376. package/clis/lobsters/newest.js +4 -1
  377. package/clis/lobsters/read.js +196 -0
  378. package/clis/lobsters/tag.js +4 -1
  379. package/clis/maimai/search-talents.js +1 -0
  380. package/clis/medium/feed.js +1 -0
  381. package/clis/medium/search.js +1 -0
  382. package/clis/medium/user.js +1 -0
  383. package/clis/mubu/doc.js +1 -0
  384. package/clis/mubu/docs.js +1 -0
  385. package/clis/mubu/notes.js +1 -0
  386. package/clis/mubu/recent.js +1 -0
  387. package/clis/mubu/search.js +1 -0
  388. package/clis/notebooklm/current.js +1 -0
  389. package/clis/notebooklm/get.js +1 -0
  390. package/clis/notebooklm/history.js +1 -0
  391. package/clis/notebooklm/list.js +1 -0
  392. package/clis/notebooklm/note-list.js +1 -0
  393. package/clis/notebooklm/notes-get.js +1 -0
  394. package/clis/notebooklm/open.js +1 -0
  395. package/clis/notebooklm/source-fulltext.js +1 -0
  396. package/clis/notebooklm/source-get.js +1 -0
  397. package/clis/notebooklm/source-guide.js +1 -0
  398. package/clis/notebooklm/source-list.js +1 -0
  399. package/clis/notebooklm/status.js +1 -0
  400. package/clis/notebooklm/summary.js +1 -0
  401. package/clis/notion/export.js +1 -0
  402. package/clis/notion/favorites.js +1 -0
  403. package/clis/notion/new.js +1 -0
  404. package/clis/notion/read.js +1 -0
  405. package/clis/notion/search.js +1 -0
  406. package/clis/notion/sidebar.js +1 -0
  407. package/clis/notion/status.js +1 -0
  408. package/clis/notion/write.js +1 -0
  409. package/clis/nowcoder/companies.js +1 -0
  410. package/clis/nowcoder/creators.js +1 -0
  411. package/clis/nowcoder/detail.js +1 -0
  412. package/clis/nowcoder/experience.js +1 -0
  413. package/clis/nowcoder/hot.js +1 -0
  414. package/clis/nowcoder/jobs.js +1 -0
  415. package/clis/nowcoder/notifications.js +1 -0
  416. package/clis/nowcoder/papers.js +1 -0
  417. package/clis/nowcoder/practice.js +1 -0
  418. package/clis/nowcoder/recommend.js +1 -0
  419. package/clis/nowcoder/referral.js +1 -0
  420. package/clis/nowcoder/salary.js +1 -0
  421. package/clis/nowcoder/search.js +1 -0
  422. package/clis/nowcoder/suggest.js +1 -0
  423. package/clis/nowcoder/topics.js +1 -0
  424. package/clis/nowcoder/trending.js +1 -0
  425. package/clis/ones/login.js +1 -0
  426. package/clis/ones/logout.js +1 -0
  427. package/clis/ones/me.js +1 -0
  428. package/clis/ones/my-tasks.js +1 -0
  429. package/clis/ones/task.js +1 -0
  430. package/clis/ones/tasks.js +1 -0
  431. package/clis/ones/token-info.js +1 -0
  432. package/clis/ones/worklog.js +1 -0
  433. package/clis/openreview/openreview.test.js +345 -0
  434. package/clis/openreview/paper.js +43 -0
  435. package/clis/openreview/reviews.js +131 -0
  436. package/clis/openreview/search.js +46 -0
  437. package/clis/openreview/utils.js +158 -0
  438. package/clis/openreview/venue.js +63 -0
  439. package/clis/paperreview/feedback.js +1 -0
  440. package/clis/paperreview/review.js +1 -0
  441. package/clis/paperreview/submit.js +1 -0
  442. package/clis/pixiv/detail.js +1 -0
  443. package/clis/pixiv/download.js +1 -0
  444. package/clis/pixiv/illusts.js +2 -1
  445. package/clis/pixiv/ranking.js +2 -1
  446. package/clis/pixiv/search.js +2 -1
  447. package/clis/pixiv/user.js +2 -0
  448. package/clis/powerchina/search.js +1 -0
  449. package/clis/producthunt/browse.js +1 -0
  450. package/clis/producthunt/hot.js +1 -0
  451. package/clis/producthunt/posts.js +1 -0
  452. package/clis/producthunt/today.js +1 -0
  453. package/clis/quark/ls.js +1 -0
  454. package/clis/quark/mkdir.js +1 -0
  455. package/clis/quark/mv.js +1 -0
  456. package/clis/quark/rename.js +1 -0
  457. package/clis/quark/rm.js +1 -0
  458. package/clis/quark/save.js +1 -0
  459. package/clis/quark/share-tree.js +1 -0
  460. package/clis/reddit/comment.js +1 -0
  461. package/clis/reddit/frontpage.js +1 -0
  462. package/clis/reddit/hot.js +6 -1
  463. package/clis/reddit/hot.test.js +18 -0
  464. package/clis/reddit/popular.js +1 -0
  465. package/clis/reddit/read.js +1 -0
  466. package/clis/reddit/save.js +1 -0
  467. package/clis/reddit/saved.js +1 -0
  468. package/clis/reddit/search.js +1 -0
  469. package/clis/reddit/subreddit.js +1 -0
  470. package/clis/reddit/subscribe.js +1 -0
  471. package/clis/reddit/upvote.js +1 -0
  472. package/clis/reddit/upvoted.js +1 -0
  473. package/clis/reddit/user-comments.js +1 -0
  474. package/clis/reddit/user-posts.js +1 -0
  475. package/clis/reddit/user.js +1 -0
  476. package/clis/reuters/search.js +1 -0
  477. package/clis/sinablog/article.js +1 -0
  478. package/clis/sinablog/hot.js +1 -0
  479. package/clis/sinablog/search.js +1 -0
  480. package/clis/sinablog/user.js +1 -0
  481. package/clis/sinafinance/news.js +1 -0
  482. package/clis/sinafinance/rolling-news.js +1 -0
  483. package/clis/sinafinance/stock-rank.js +1 -0
  484. package/clis/sinafinance/stock.js +1 -0
  485. package/clis/smzdm/search.js +1 -0
  486. package/clis/spotify/spotify.js +11 -0
  487. package/clis/stackoverflow/bounties.js +11 -3
  488. package/clis/stackoverflow/hot.js +10 -2
  489. package/clis/stackoverflow/read.js +314 -0
  490. package/clis/stackoverflow/search.js +10 -2
  491. package/clis/stackoverflow/stackoverflow.test.js +346 -0
  492. package/clis/stackoverflow/unanswered.js +9 -2
  493. package/clis/steam/top-sellers.js +1 -0
  494. package/clis/substack/feed.js +1 -0
  495. package/clis/substack/publication.js +1 -0
  496. package/clis/substack/search.js +1 -0
  497. package/clis/taobao/add-cart.js +1 -0
  498. package/clis/taobao/cart.js +1 -0
  499. package/clis/taobao/detail.js +1 -0
  500. package/clis/taobao/reviews.js +1 -0
  501. package/clis/taobao/search.js +1 -0
  502. package/clis/tdx/hot-rank.js +1 -0
  503. package/clis/ths/hot-rank.js +1 -0
  504. package/clis/tieba/hot.js +2 -1
  505. package/clis/tieba/posts.js +1 -0
  506. package/clis/tieba/read.js +1 -0
  507. package/clis/tieba/search.js +2 -1
  508. package/clis/tiktok/comment.js +1 -0
  509. package/clis/tiktok/explore.js +1 -0
  510. package/clis/tiktok/follow.js +1 -0
  511. package/clis/tiktok/following.js +1 -0
  512. package/clis/tiktok/friends.js +1 -0
  513. package/clis/tiktok/like.js +1 -0
  514. package/clis/tiktok/live.js +1 -0
  515. package/clis/tiktok/notifications.js +1 -0
  516. package/clis/tiktok/profile.js +1 -0
  517. package/clis/tiktok/save.js +1 -0
  518. package/clis/tiktok/search.js +1 -0
  519. package/clis/tiktok/unfollow.js +1 -0
  520. package/clis/tiktok/unlike.js +1 -0
  521. package/clis/tiktok/unsave.js +1 -0
  522. package/clis/tiktok/user.js +1 -0
  523. package/clis/toutiao/articles.js +1 -0
  524. package/clis/twitter/accept.js +1 -0
  525. package/clis/twitter/article.js +1 -0
  526. package/clis/twitter/block.js +1 -0
  527. package/clis/twitter/bookmark.js +1 -0
  528. package/clis/twitter/bookmarks.js +2 -1
  529. package/clis/twitter/delete.js +1 -0
  530. package/clis/twitter/download.js +1 -0
  531. package/clis/twitter/follow.js +1 -0
  532. package/clis/twitter/followers.js +1 -0
  533. package/clis/twitter/following.js +1 -0
  534. package/clis/twitter/hide-reply.js +1 -0
  535. package/clis/twitter/like.js +1 -0
  536. package/clis/twitter/likes.js +2 -1
  537. package/clis/twitter/list-add.js +1 -0
  538. package/clis/twitter/list-remove.js +1 -0
  539. package/clis/twitter/list-tweets.js +1 -0
  540. package/clis/twitter/lists.js +1 -0
  541. package/clis/twitter/notifications.js +1 -0
  542. package/clis/twitter/post.js +1 -0
  543. package/clis/twitter/profile.js +1 -0
  544. package/clis/twitter/reply-dm.js +1 -0
  545. package/clis/twitter/reply.js +1 -0
  546. package/clis/twitter/search.js +1 -0
  547. package/clis/twitter/thread.js +1 -0
  548. package/clis/twitter/timeline.js +1 -0
  549. package/clis/twitter/trending.js +11 -12
  550. package/clis/twitter/trending.test.js +15 -0
  551. package/clis/twitter/tweets.js +2 -1
  552. package/clis/twitter/tweets.test.js +2 -2
  553. package/clis/twitter/unblock.js +1 -0
  554. package/clis/twitter/unbookmark.js +1 -0
  555. package/clis/twitter/unfollow.js +1 -0
  556. package/clis/uiverse/code.js +1 -0
  557. package/clis/uiverse/preview.js +1 -0
  558. package/clis/v2ex/daily.js +1 -0
  559. package/clis/v2ex/hot.js +1 -0
  560. package/clis/v2ex/latest.js +1 -0
  561. package/clis/v2ex/me.js +1 -0
  562. package/clis/v2ex/member.js +1 -0
  563. package/clis/v2ex/node.js +1 -0
  564. package/clis/v2ex/nodes.js +1 -0
  565. package/clis/v2ex/notifications.js +1 -0
  566. package/clis/v2ex/replies.js +1 -0
  567. package/clis/v2ex/topic.js +1 -0
  568. package/clis/v2ex/user.js +1 -0
  569. package/clis/wanfang/search.js +1 -0
  570. package/clis/web/read.js +1 -0
  571. package/clis/weibo/comments.js +1 -0
  572. package/clis/weibo/favorites.js +1 -0
  573. package/clis/weibo/feed.js +3 -1
  574. package/clis/weibo/hot.js +1 -0
  575. package/clis/weibo/me.js +1 -0
  576. package/clis/weibo/post.js +1 -0
  577. package/clis/weibo/publish.js +1 -0
  578. package/clis/weibo/search.js +8 -2
  579. package/clis/weibo/user.js +1 -0
  580. package/clis/weixin/create-draft.js +1 -0
  581. package/clis/weixin/download.js +1 -0
  582. package/clis/weixin/drafts.js +1 -0
  583. package/clis/weread/ai-outline.js +1 -0
  584. package/clis/weread/book.js +1 -0
  585. package/clis/weread/highlights.js +1 -0
  586. package/clis/weread/notebooks.js +1 -0
  587. package/clis/weread/notes.js +1 -0
  588. package/clis/weread/ranking.js +1 -0
  589. package/clis/weread/search.js +1 -0
  590. package/clis/weread/shelf.js +1 -0
  591. package/clis/wikipedia/random.js +1 -0
  592. package/clis/wikipedia/search.js +1 -0
  593. package/clis/wikipedia/summary.js +1 -0
  594. package/clis/wikipedia/trending.js +1 -0
  595. package/clis/xianyu/chat.js +1 -0
  596. package/clis/xianyu/item.js +1 -0
  597. package/clis/xianyu/search.js +1 -0
  598. package/clis/xiaoe/catalog.js +2 -1
  599. package/clis/xiaoe/content.js +1 -0
  600. package/clis/xiaoe/courses.js +1 -0
  601. package/clis/xiaoe/detail.js +1 -0
  602. package/clis/xiaoe/play-url.js +1 -0
  603. package/clis/xiaohongshu/comments.js +1 -0
  604. package/clis/xiaohongshu/creator-note-detail.js +1 -0
  605. package/clis/xiaohongshu/creator-notes-summary.js +1 -0
  606. package/clis/xiaohongshu/creator-notes.js +1 -0
  607. package/clis/xiaohongshu/creator-profile.js +1 -0
  608. package/clis/xiaohongshu/creator-stats.js +1 -0
  609. package/clis/xiaohongshu/download.js +1 -0
  610. package/clis/xiaohongshu/feed.js +2 -1
  611. package/clis/xiaohongshu/note.js +1 -0
  612. package/clis/xiaohongshu/notifications.js +1 -0
  613. package/clis/xiaohongshu/publish.js +1 -0
  614. package/clis/xiaohongshu/search.js +1 -0
  615. package/clis/xiaohongshu/user.js +1 -0
  616. package/clis/xiaoyuzhou/download.js +1 -0
  617. package/clis/xiaoyuzhou/episode.js +1 -0
  618. package/clis/xiaoyuzhou/podcast-episodes.js +1 -0
  619. package/clis/xiaoyuzhou/podcast.js +1 -0
  620. package/clis/xiaoyuzhou/transcript.js +1 -0
  621. package/clis/xueqiu/comments.js +1 -0
  622. package/clis/xueqiu/earnings-date.js +1 -0
  623. package/clis/xueqiu/feed.js +1 -0
  624. package/clis/xueqiu/fund-holdings.js +1 -0
  625. package/clis/xueqiu/fund-snapshot.js +1 -0
  626. package/clis/xueqiu/groups.js +1 -0
  627. package/clis/xueqiu/hot-stock.js +1 -0
  628. package/clis/xueqiu/hot.js +1 -0
  629. package/clis/xueqiu/kline.js +1 -0
  630. package/clis/xueqiu/search.js +1 -0
  631. package/clis/xueqiu/stock.js +1 -0
  632. package/clis/xueqiu/watchlist.js +1 -0
  633. package/clis/yahoo-finance/quote.js +1 -0
  634. package/clis/yollomi/background.js +1 -0
  635. package/clis/yollomi/edit.js +1 -0
  636. package/clis/yollomi/face-swap.js +1 -0
  637. package/clis/yollomi/generate.js +1 -0
  638. package/clis/yollomi/models.js +1 -0
  639. package/clis/yollomi/object-remover.js +1 -0
  640. package/clis/yollomi/remove-bg.js +1 -0
  641. package/clis/yollomi/restore.js +1 -0
  642. package/clis/yollomi/try-on.js +1 -0
  643. package/clis/yollomi/upload.js +1 -0
  644. package/clis/yollomi/upscale.js +1 -0
  645. package/clis/yollomi/video.js +1 -0
  646. package/clis/youtube/channel.js +1 -0
  647. package/clis/youtube/comments.js +1 -0
  648. package/clis/youtube/feed.js +8 -7
  649. package/clis/youtube/feed.test.js +131 -0
  650. package/clis/youtube/history.js +1 -0
  651. package/clis/youtube/like.js +1 -0
  652. package/clis/youtube/playlist.js +1 -0
  653. package/clis/youtube/search.js +1 -0
  654. package/clis/youtube/subscribe.js +1 -0
  655. package/clis/youtube/subscriptions.js +1 -0
  656. package/clis/youtube/transcript.js +1 -0
  657. package/clis/youtube/unlike.js +1 -0
  658. package/clis/youtube/unsubscribe.js +1 -0
  659. package/clis/youtube/video.js +1 -0
  660. package/clis/youtube/watch-later.js +1 -0
  661. package/clis/yuanbao/ask.js +1 -0
  662. package/clis/yuanbao/new.js +1 -0
  663. package/clis/zhihu/answer.js +1 -0
  664. package/clis/zhihu/collection.js +1 -0
  665. package/clis/zhihu/collections.js +1 -0
  666. package/clis/zhihu/comment.js +1 -0
  667. package/clis/zhihu/download.js +1 -0
  668. package/clis/zhihu/favorite.js +1 -0
  669. package/clis/zhihu/follow.js +1 -0
  670. package/clis/zhihu/hot.js +1 -0
  671. package/clis/zhihu/like.js +1 -0
  672. package/clis/zhihu/question.js +1 -0
  673. package/clis/zhihu/search.js +1 -0
  674. package/clis/zlibrary/info.js +1 -0
  675. package/clis/zlibrary/search.js +1 -0
  676. package/clis/zsxq/dynamics.js +1 -0
  677. package/clis/zsxq/groups.js +1 -0
  678. package/clis/zsxq/search.js +1 -0
  679. package/clis/zsxq/topic.js +1 -0
  680. package/clis/zsxq/topics.js +1 -0
  681. package/dist/src/adapter-shadow.d.ts +11 -0
  682. package/dist/src/adapter-shadow.js +72 -0
  683. package/dist/src/adapter-shadow.test.d.ts +1 -0
  684. package/dist/src/adapter-shadow.test.js +49 -0
  685. package/dist/src/adapter-source.test.js +1 -1
  686. package/dist/src/browser/analyze.test.js +2 -0
  687. package/dist/src/browser/base-page.d.ts +15 -2
  688. package/dist/src/browser/base-page.js +159 -8
  689. package/dist/src/browser/base-page.test.js +103 -1
  690. package/dist/src/browser/cdp.js +54 -0
  691. package/dist/src/browser/cdp.test.js +26 -0
  692. package/dist/src/browser/dom-helpers.d.ts +1 -1
  693. package/dist/src/browser/dom-helpers.js +15 -3
  694. package/dist/src/browser/page.d.ts +1 -0
  695. package/dist/src/browser/page.js +7 -1
  696. package/dist/src/browser/page.test.js +17 -0
  697. package/dist/src/browser/target-resolver.d.ts +17 -2
  698. package/dist/src/browser/target-resolver.js +85 -4
  699. package/dist/src/browser/verify-fixture.d.ts +7 -1
  700. package/dist/src/browser/verify-fixture.js +105 -0
  701. package/dist/src/browser/verify-fixture.test.js +59 -1
  702. package/dist/src/build-manifest.d.ts +68 -33
  703. package/dist/src/build-manifest.js +178 -29
  704. package/dist/src/build-manifest.test.js +85 -5
  705. package/dist/src/capabilityRouting.test.js +1 -1
  706. package/dist/src/cli.js +150 -11
  707. package/dist/src/cli.test.js +237 -0
  708. package/dist/src/commanderAdapter.d.ts +1 -1
  709. package/dist/src/commanderAdapter.js +17 -7
  710. package/dist/src/commanderAdapter.test.js +7 -6
  711. package/dist/src/convention-audit.d.ts +50 -0
  712. package/dist/src/convention-audit.js +546 -0
  713. package/dist/src/convention-audit.test.d.ts +1 -0
  714. package/dist/src/convention-audit.test.js +226 -0
  715. package/dist/src/discovery.js +2 -0
  716. package/dist/src/doctor.d.ts +2 -0
  717. package/dist/src/doctor.js +6 -0
  718. package/dist/src/doctor.test.js +36 -1
  719. package/dist/src/engine.test.js +10 -10
  720. package/dist/src/execution.js +1 -1
  721. package/dist/src/execution.test.js +9 -9
  722. package/dist/src/help.d.ts +15 -0
  723. package/dist/src/help.js +149 -0
  724. package/dist/src/main.js +13 -7
  725. package/dist/src/manifest-types.d.ts +41 -0
  726. package/dist/src/manifest-types.js +9 -0
  727. package/dist/src/plugin.test.js +26 -26
  728. package/dist/src/registry.d.ts +5 -0
  729. package/dist/src/registry.js +8 -0
  730. package/dist/src/registry.test.js +27 -20
  731. package/dist/src/serialization.d.ts +4 -0
  732. package/dist/src/serialization.js +27 -1
  733. package/dist/src/serialization.test.js +24 -2
  734. package/dist/src/types.d.ts +2 -0
  735. package/package.json +5 -2
  736. package/scripts/check-listing-id-pairing.mjs +193 -0
  737. package/scripts/check-silent-column-drop.mjs +105 -0
  738. package/scripts/check-typed-error-lint.mjs +118 -0
  739. package/scripts/silent-column-drop-baseline.json +962 -0
  740. package/scripts/typed-error-lint-baseline.json +1586 -0
@@ -7,13 +7,14 @@ describe('cli() registration', () => {
7
7
  it('registers a command and returns it', () => {
8
8
  const cmd = cli({
9
9
  site: 'test-registry',
10
- name: 'hello',
10
+ name: 'hello', access: 'read',
11
11
  description: 'A test command',
12
12
  strategy: Strategy.PUBLIC,
13
13
  browser: false,
14
14
  });
15
15
  expect(cmd.site).toBe('test-registry');
16
16
  expect(cmd.name).toBe('hello');
17
+ expect(cmd.access).toBe('read');
17
18
  expect(cmd.strategy).toBe(Strategy.PUBLIC);
18
19
  expect(cmd.browser).toBe(false);
19
20
  expect(cmd.args).toEqual([]);
@@ -21,7 +22,7 @@ describe('cli() registration', () => {
21
22
  it('puts registered command in the registry', () => {
22
23
  cli({
23
24
  site: 'test-registry',
24
- name: 'registered',
25
+ name: 'registered', access: 'read',
25
26
  description: 'test',
26
27
  });
27
28
  const registry = getRegistry();
@@ -30,7 +31,7 @@ describe('cli() registration', () => {
30
31
  it('defaults strategy to COOKIE when browser is true', () => {
31
32
  const cmd = cli({
32
33
  site: 'test-registry',
33
- name: 'default-strategy',
34
+ name: 'default-strategy', access: 'read',
34
35
  });
35
36
  expect(cmd.strategy).toBe(Strategy.COOKIE);
36
37
  expect(cmd.browser).toBe(true);
@@ -38,7 +39,7 @@ describe('cli() registration', () => {
38
39
  it('defaults strategy to PUBLIC when browser is false', () => {
39
40
  const cmd = cli({
40
41
  site: 'test-registry',
41
- name: 'no-browser',
42
+ name: 'no-browser', access: 'read',
42
43
  browser: false,
43
44
  });
44
45
  expect(cmd.strategy).toBe(Strategy.PUBLIC);
@@ -46,7 +47,7 @@ describe('cli() registration', () => {
46
47
  it('preserves LOCAL strategy on registration', () => {
47
48
  const cmd = cli({
48
49
  site: 'test-registry',
49
- name: 'local-strategy',
50
+ name: 'local-strategy', access: 'read',
50
51
  description: 'reads local credentials',
51
52
  strategy: Strategy.LOCAL,
52
53
  browser: false,
@@ -55,15 +56,15 @@ describe('cli() registration', () => {
55
56
  expect(cmd.browser).toBe(false);
56
57
  });
57
58
  it('overwrites existing command on re-registration', () => {
58
- cli({ site: 'test-registry', name: 'overwrite', description: 'v1' });
59
- cli({ site: 'test-registry', name: 'overwrite', description: 'v2' });
59
+ cli({ site: 'test-registry', name: 'overwrite', access: 'read', description: 'v1' });
60
+ cli({ site: 'test-registry', name: 'overwrite', access: 'read', description: 'v2' });
60
61
  const reg = getRegistry();
61
62
  expect(reg.get('test-registry/overwrite')?.description).toBe('v2');
62
63
  });
63
64
  it('registers aliases as alternate registry keys for the same command', () => {
64
65
  const cmd = cli({
65
66
  site: 'test-registry',
66
- name: 'canonical',
67
+ name: 'canonical', access: 'read',
67
68
  description: 'test aliases',
68
69
  aliases: ['compat', 'legacy-name'],
69
70
  });
@@ -76,18 +77,24 @@ describe('cli() registration', () => {
76
77
  it('preserves defaultFormat on the registered command', () => {
77
78
  const cmd = cli({
78
79
  site: 'test-registry',
79
- name: 'plain-default',
80
+ name: 'plain-default', access: 'read',
80
81
  description: 'prefers plain output',
81
82
  defaultFormat: 'plain',
82
83
  });
83
84
  expect(cmd.defaultFormat).toBe('plain');
84
85
  expect(getRegistry().get('test-registry/plain-default')?.defaultFormat).toBe('plain');
85
86
  });
87
+ it('rejects commands without explicit access metadata', () => {
88
+ expect(() => cli({
89
+ site: 'test-registry',
90
+ name: 'missing-access',
91
+ })).toThrow("Command test-registry/missing-access must declare access: 'read' | 'write'");
92
+ });
86
93
  });
87
94
  describe('fullName', () => {
88
95
  it('returns site/name', () => {
89
96
  const cmd = {
90
- site: 'bilibili', name: 'hot', description: '', args: [],
97
+ site: 'bilibili', name: 'hot', access: 'read', description: '', args: [],
91
98
  };
92
99
  expect(fullName(cmd)).toBe('bilibili/hot');
93
100
  });
@@ -95,14 +102,14 @@ describe('fullName', () => {
95
102
  describe('strategyLabel', () => {
96
103
  it('returns strategy string', () => {
97
104
  const cmd = {
98
- site: 'test', name: 'test', description: '', args: [],
105
+ site: 'test', name: 'test', access: 'read', description: '', args: [],
99
106
  strategy: Strategy.INTERCEPT,
100
107
  };
101
108
  expect(strategyLabel(cmd)).toBe('intercept');
102
109
  });
103
110
  it('returns public when no strategy set', () => {
104
111
  const cmd = {
105
- site: 'test', name: 'test', description: '', args: [],
112
+ site: 'test', name: 'test', access: 'read', description: '', args: [],
106
113
  };
107
114
  expect(strategyLabel(cmd)).toBe('public');
108
115
  });
@@ -111,7 +118,7 @@ describe('registerCommand', () => {
111
118
  it('registers a pre-built command', () => {
112
119
  const cmd = {
113
120
  site: 'test-registry',
114
- name: 'direct-reg',
121
+ name: 'direct-reg', access: 'read',
115
122
  description: 'directly registered',
116
123
  args: [],
117
124
  strategy: Strategy.HEADER,
@@ -125,7 +132,7 @@ describe('registerCommand', () => {
125
132
  describe('normalizeCommand (via registerCommand)', () => {
126
133
  it('COOKIE + domain → navigateBefore is the domain URL', () => {
127
134
  registerCommand({
128
- site: 'test-norm', name: 'cookie-domain', description: '', args: [],
135
+ site: 'test-norm', name: 'cookie-domain', access: 'read', description: '', args: [],
129
136
  strategy: Strategy.COOKIE, domain: 'x.com',
130
137
  });
131
138
  const cmd = getRegistry().get('test-norm/cookie-domain');
@@ -134,7 +141,7 @@ describe('normalizeCommand (via registerCommand)', () => {
134
141
  });
135
142
  it('COOKIE without domain → navigateBefore is true (auth context, no URL)', () => {
136
143
  registerCommand({
137
- site: 'test-norm', name: 'cookie-nodomain', description: '', args: [],
144
+ site: 'test-norm', name: 'cookie-nodomain', access: 'read', description: '', args: [],
138
145
  strategy: Strategy.COOKIE,
139
146
  });
140
147
  const cmd = getRegistry().get('test-norm/cookie-nodomain');
@@ -143,7 +150,7 @@ describe('normalizeCommand (via registerCommand)', () => {
143
150
  });
144
151
  it('INTERCEPT → navigateBefore is true (auth context)', () => {
145
152
  registerCommand({
146
- site: 'test-norm', name: 'intercept', description: '', args: [],
153
+ site: 'test-norm', name: 'intercept', access: 'read', description: '', args: [],
147
154
  strategy: Strategy.INTERCEPT, domain: 'example.com',
148
155
  });
149
156
  const cmd = getRegistry().get('test-norm/intercept');
@@ -152,7 +159,7 @@ describe('normalizeCommand (via registerCommand)', () => {
152
159
  });
153
160
  it('PUBLIC → browser false, navigateBefore undefined', () => {
154
161
  registerCommand({
155
- site: 'test-norm', name: 'public', description: '', args: [],
162
+ site: 'test-norm', name: 'public', access: 'read', description: '', args: [],
156
163
  strategy: Strategy.PUBLIC,
157
164
  });
158
165
  const cmd = getRegistry().get('test-norm/public');
@@ -161,7 +168,7 @@ describe('normalizeCommand (via registerCommand)', () => {
161
168
  });
162
169
  it('LOCAL → browser false, navigateBefore undefined', () => {
163
170
  registerCommand({
164
- site: 'test-norm', name: 'local', description: '', args: [],
171
+ site: 'test-norm', name: 'local', access: 'read', description: '', args: [],
165
172
  strategy: Strategy.LOCAL,
166
173
  });
167
174
  const cmd = getRegistry().get('test-norm/local');
@@ -172,7 +179,7 @@ describe('normalizeCommand (via registerCommand)', () => {
172
179
  });
173
180
  it('explicit navigateBefore: false overrides COOKIE + domain', () => {
174
181
  registerCommand({
175
- site: 'test-norm', name: 'cookie-override', description: '', args: [],
182
+ site: 'test-norm', name: 'cookie-override', access: 'read', description: '', args: [],
176
183
  strategy: Strategy.COOKIE, domain: 'amazon.com', navigateBefore: false,
177
184
  });
178
185
  const cmd = getRegistry().get('test-norm/cookie-override');
@@ -181,7 +188,7 @@ describe('normalizeCommand (via registerCommand)', () => {
181
188
  });
182
189
  it('explicit navigateBefore URL overrides strategy default', () => {
183
190
  registerCommand({
184
- site: 'test-norm', name: 'explicit-url', description: '', args: [],
191
+ site: 'test-norm', name: 'explicit-url', access: 'read', description: '', args: [],
185
192
  strategy: Strategy.COOKIE, domain: 'x.com',
186
193
  navigateBefore: 'https://x.com/explore',
187
194
  });
@@ -24,15 +24,19 @@ export declare function serializeCommand(cmd: CliCommand): {
24
24
  name: string;
25
25
  aliases: string[];
26
26
  description: string;
27
+ access: import("./registry.js").CommandAccess;
27
28
  strategy: string;
28
29
  browser: boolean;
29
30
  args: SerializedArg[];
30
31
  columns: string[];
31
32
  domain: string | null;
33
+ example: string;
32
34
  deprecated: string | boolean | null;
33
35
  replacedBy: string | null;
34
36
  };
35
37
  /** Human-readable arg summary: `<required> [optional]` style. */
36
38
  export declare function formatArgSummary(args: Arg[]): string;
39
+ /** Agent-facing canonical invocation. Adapter authors may override with `example`. */
40
+ export declare function formatCommandExample(cmd: CliCommand): string;
37
41
  /** Generate the --help appendix showing registry metadata not exposed by Commander. */
38
42
  export declare function formatRegistryHelpText(cmd: CliCommand): string;
@@ -26,11 +26,13 @@ export function serializeCommand(cmd) {
26
26
  name: cmd.name,
27
27
  aliases: cmd.aliases ?? [],
28
28
  description: cmd.description,
29
+ access: cmd.access,
29
30
  strategy: strategyLabel(cmd),
30
31
  browser: !!cmd.browser,
31
32
  args: cmd.args.map(serializeArg),
32
33
  columns: cmd.columns ?? [],
33
34
  domain: cmd.domain ?? null,
35
+ example: formatCommandExample(cmd),
34
36
  deprecated: cmd.deprecated ?? null,
35
37
  replacedBy: cmd.replacedBy ?? null,
36
38
  };
@@ -51,6 +53,29 @@ function summarizeChoices(choices) {
51
53
  return choices.join(', ');
52
54
  return `${choices.slice(0, 4).join(', ')}, ... (+${choices.length - 4} more)`;
53
55
  }
56
+ function formatValuePlaceholder(name) {
57
+ return `<${name}>`;
58
+ }
59
+ /** Agent-facing canonical invocation. Adapter authors may override with `example`. */
60
+ export function formatCommandExample(cmd) {
61
+ if (cmd.example?.trim())
62
+ return cmd.example.trim();
63
+ const parts = ['opencli', cmd.site, cmd.name];
64
+ for (const arg of cmd.args) {
65
+ if (arg.positional && arg.required) {
66
+ parts.push(formatValuePlaceholder(arg.name));
67
+ }
68
+ }
69
+ for (const arg of cmd.args) {
70
+ if (arg.positional || !arg.required)
71
+ continue;
72
+ parts.push(`--${arg.name}`);
73
+ if (arg.type !== 'bool' && arg.type !== 'boolean')
74
+ parts.push(formatValuePlaceholder(arg.name));
75
+ }
76
+ parts.push('-f', 'yaml');
77
+ return parts.join(' ');
78
+ }
54
79
  /** Generate the --help appendix showing registry metadata not exposed by Commander. */
55
80
  export function formatRegistryHelpText(cmd) {
56
81
  const lines = [];
@@ -61,7 +86,7 @@ export function formatRegistryHelpText(cmd) {
61
86
  lines.push(` ${prefix}: ${summarizeChoices(a.choices)}${def}`);
62
87
  }
63
88
  const meta = [];
64
- meta.push(`Strategy: ${strategyLabel(cmd)}`);
89
+ meta.push(`Access: ${cmd.access}`);
65
90
  meta.push(`Browser: ${cmd.browser ? 'yes' : 'no'}`);
66
91
  if (cmd.domain)
67
92
  meta.push(`Domain: ${cmd.domain}`);
@@ -72,6 +97,7 @@ export function formatRegistryHelpText(cmd) {
72
97
  if (cmd.aliases?.length)
73
98
  meta.push(`Aliases: ${cmd.aliases.join(', ')}`);
74
99
  lines.push(meta.join(' | '));
100
+ lines.push(`Example: ${formatCommandExample(cmd)}`);
75
101
  if (cmd.columns?.length)
76
102
  lines.push(`Output columns: ${cmd.columns.join(', ')}`);
77
103
  return '\n' + lines.join('\n') + '\n';
@@ -1,11 +1,11 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
  import { Strategy } from './registry.js';
3
- import { formatRegistryHelpText, serializeCommand } from './serialization.js';
3
+ import { formatCommandExample, formatRegistryHelpText, serializeCommand } from './serialization.js';
4
4
  describe('formatRegistryHelpText', () => {
5
5
  it('summarizes long choices lists so help text stays readable', () => {
6
6
  const cmd = {
7
7
  site: 'demo',
8
- name: 'dynamic',
8
+ name: 'dynamic', access: 'read',
9
9
  description: 'Demo command',
10
10
  strategy: Strategy.PUBLIC,
11
11
  browser: false,
@@ -24,6 +24,7 @@ describe('formatRegistryHelpText', () => {
24
24
  const cmd = {
25
25
  site: 'demo',
26
26
  name: 'get',
27
+ access: 'read',
27
28
  aliases: ['metadata'],
28
29
  description: 'Demo command',
29
30
  strategy: Strategy.COOKIE,
@@ -32,8 +33,29 @@ describe('formatRegistryHelpText', () => {
32
33
  };
33
34
  expect(serializeCommand(cmd)).toMatchObject({
34
35
  command: 'demo/get',
36
+ access: 'read',
35
37
  aliases: ['metadata'],
36
38
  });
37
39
  expect(formatRegistryHelpText(cmd)).toContain('Aliases: metadata');
38
40
  });
41
+ it('surfaces access and canonical examples instead of strategy as primary help metadata', () => {
42
+ const cmd = {
43
+ site: 'bilibili',
44
+ name: 'hot',
45
+ access: 'read',
46
+ description: 'Bilibili hot videos',
47
+ strategy: Strategy.COOKIE,
48
+ browser: true,
49
+ args: [],
50
+ };
51
+ expect(formatCommandExample(cmd)).toBe('opencli bilibili hot -f yaml');
52
+ expect(serializeCommand(cmd)).toMatchObject({
53
+ command: 'bilibili/hot',
54
+ access: 'read',
55
+ example: 'opencli bilibili hot -f yaml',
56
+ });
57
+ expect(formatRegistryHelpText(cmd)).toContain('Access: read');
58
+ expect(formatRegistryHelpText(cmd)).toContain('Example: opencli bilibili hot -f yaml');
59
+ expect(formatRegistryHelpText(cmd)).not.toContain('Strategy:');
60
+ });
39
61
  });
@@ -130,6 +130,8 @@ export interface IPage {
130
130
  setActivePage?(page?: string): void;
131
131
  /** Send a raw CDP command via chrome.debugger passthrough. */
132
132
  cdp?(method: string, params?: Record<string, unknown>): Promise<unknown>;
133
+ /** Accept or dismiss the currently open JavaScript alert/confirm/prompt dialog. */
134
+ handleJavaScriptDialog?(accept: boolean, promptText?: string): Promise<void>;
133
135
  /** List cross-origin iframe targets in snapshot order. */
134
136
  frames?(): Promise<Array<{
135
137
  index: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jackwener/opencli",
3
- "version": "1.7.10",
3
+ "version": "1.7.12",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -42,7 +42,7 @@
42
42
  "dev": "tsx src/main.ts",
43
43
  "dev:bun": "bun src/main.ts",
44
44
  "build": "npm run clean-dist && tsc && npm run copy-yaml && npm run build-manifest",
45
- "build-manifest": "node dist/src/build-manifest.js",
45
+ "build-manifest": "tsx src/build-manifest.ts",
46
46
  "clean-dist": "node scripts/clean-dist.cjs",
47
47
  "copy-yaml": "node scripts/copy-yaml.cjs",
48
48
  "start": "node dist/src/main.js",
@@ -57,6 +57,9 @@
57
57
  "test:adapter": "vitest run --project adapter",
58
58
  "test:all": "vitest run",
59
59
  "test:e2e": "vitest run --project e2e",
60
+ "advise:listing-id-pairing": "node scripts/check-listing-id-pairing.mjs",
61
+ "check:silent-column-drop": "node scripts/check-silent-column-drop.mjs",
62
+ "check:typed-error-lint": "node scripts/check-typed-error-lint.mjs",
60
63
  "docs:dev": "vitepress dev docs",
61
64
  "docs:build": "vitepress build docs",
62
65
  "docs:preview": "vitepress preview docs"
@@ -0,0 +1,193 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * check-listing-id-pairing.mjs — advisory report on listing↔detail id round-tripping.
4
+ *
5
+ * Soft convention (NOT a CI gate): when a site exposes both a listing-class
6
+ * command (search / hot / recent / trending / top / feed / popular / new /
7
+ * list) AND a detail-class command (read / article / paper / post / detail /
8
+ * view / job / page / book / movie / show / chapter / question / answer /
9
+ * tweet / video / track), it's usually nicer for agents if every listing row
10
+ * carries an id-shaped column whose value round-trips into the detail
11
+ * command. Without that, the agent has to re-search by title or scrape a URL
12
+ * to follow up.
13
+ *
14
+ * Why advisory and not a gate: whether a listing should pair with a detail
15
+ * is a case-by-case product/UX call (topic-string trending, profile-attribute
16
+ * key/value rows, UI-only sessions etc. legitimately don't pair). Forcing
17
+ * authors through an exempt list every PR was higher cognitive cost than the
18
+ * silent-loss bugs the rule actually catches. See PR #1311 thread for the
19
+ * "anti-pattern vs case-by-case" filter.
20
+ *
21
+ * What this script does:
22
+ * 1. Group cli-manifest.json entries by site.
23
+ * 2. For each site that has both classes, walk every listing entry and
24
+ * check `columns` for at least one id-shaped name.
25
+ * 3. Print a report. Always exits 0 — never fails CI.
26
+ *
27
+ * Usage:
28
+ * node scripts/check-listing-id-pairing.mjs # print advisory report
29
+ * npm run advise:listing-id-pairing
30
+ */
31
+
32
+ import { readFileSync } from 'node:fs';
33
+ import { fileURLToPath } from 'node:url';
34
+ import { dirname, resolve } from 'node:path';
35
+
36
+ const __dirname = dirname(fileURLToPath(import.meta.url));
37
+ const MANIFEST = resolve(__dirname, '..', 'cli-manifest.json');
38
+
39
+ /**
40
+ * Listing-class commands. Each row represents a single fetchable entity
41
+ * (post / paper / job / ...). The id of that entity must round-trip into
42
+ * the site's detail command.
43
+ */
44
+ const LISTING_NAMES = new Set([
45
+ 'search', 'hot', 'recent', 'trending', 'top', 'feed', 'popular',
46
+ 'list', 'best', 'newest', 'latest', 'rising', 'controversial',
47
+ 'home', 'timeline', 'browse', 'discover', 'jobs',
48
+ 'unanswered', 'bounties', 'tag', 'user', 'venue',
49
+ 'category', 'subreddit', 'question',
50
+ ]);
51
+
52
+ /**
53
+ * Listing-class commands whose rows are sub-resources within a parent
54
+ * thread/session, NOT independently fetchable. Excluded from the rule:
55
+ *
56
+ * - `comments` / `replies` / `reviews` / `answer-list` / `thread-list`
57
+ * — rows are comments under a parent post; the detail command fetches
58
+ * the parent, not the comment
59
+ * - `ask` / `new` / `show` for AI-chat / agent-session sites — rows are
60
+ * conversation turns within one session, not separately addressable
61
+ *
62
+ * These are intentionally NOT in `LISTING_NAMES` so the rule doesn't
63
+ * fire on them.
64
+ */
65
+
66
+
67
+ const DETAIL_NAMES = new Set([
68
+ 'read', 'article', 'paper', 'post', 'detail', 'view', 'job',
69
+ 'page', 'book', 'movie', 'show-detail', 'chapter', 'tweet',
70
+ 'video', 'track', 'note', 'review', 'item', 'product', 'episode',
71
+ 'thread', 'comment-detail', 'profile-detail', 'shop',
72
+ ]);
73
+
74
+ /** Columns whose name implies "this is an id you can pass to detail". */
75
+ const ID_COLUMN_PATTERNS = [
76
+ /^id$/i,
77
+ /_id$/i,
78
+ /Id$/,
79
+ /^short_id$/i,
80
+ /^jk$/i, // indeed
81
+ /^tid$/i, // hupu / thread id
82
+ /^bvid$/i, // bilibili
83
+ /^aid$/i, // anime / bilibili av
84
+ /^asin$/i, // amazon
85
+ /^sku$/i, // jd / retail product SKU
86
+ /^isbn$/i, // book sites
87
+ /^doi$/i, // arxiv / openreview
88
+ /^slug$/i, // dev.to / lobsters short slug
89
+ /^hn_id$/i,
90
+ /^username$/i, // user-keyed detail (profile commands)
91
+ /^handle$/i,
92
+ /^uri$/i, // bluesky AT URI (at://did:.../...)
93
+ ];
94
+
95
+ function isUrlDetailCommand(entry) {
96
+ const args = Array.isArray(entry.args) ? entry.args : [];
97
+ const primaryArg = args.find((arg) => arg?.positional || arg?.required) ?? args[0];
98
+ if (!primaryArg) return false;
99
+ const name = String(primaryArg.name ?? '').toLowerCase();
100
+ if (name === 'url' || name === 'url-or-id') return true;
101
+
102
+ const help = String(primaryArg.help ?? '').toLowerCase();
103
+ if (!help) return false;
104
+
105
+ // Accept only explicit "this argument may be a URL" wording. Phrases
106
+ // like "id from URL" mean callers must extract an id before invoking
107
+ // the detail command, so listing.url must not satisfy the id-pair gate.
108
+ return (
109
+ /^full\b[^()]*\burl\b/.test(help) ||
110
+ /\burl\s+or\s+[^()]*\bid\b/.test(help) ||
111
+ /\bor\s+(?:a\s+)?full\b[^()]*\burl\b/.test(help) ||
112
+ /\bor\s+url\b/.test(help) ||
113
+ /\burl\s*,\s*or\b/.test(help)
114
+ );
115
+ }
116
+
117
+ function isIdColumn(col, detailCommands) {
118
+ if (ID_COLUMN_PATTERNS.some((re) => re.test(col))) return true;
119
+ if (/^url$/i.test(col)) {
120
+ return detailCommands.some(isUrlDetailCommand);
121
+ }
122
+ return false;
123
+ }
124
+
125
+ function classify(name) {
126
+ if (LISTING_NAMES.has(name)) return 'listing';
127
+ if (DETAIL_NAMES.has(name)) return 'detail';
128
+ return 'other';
129
+ }
130
+
131
+ function main() {
132
+ const manifest = JSON.parse(readFileSync(MANIFEST, 'utf8'));
133
+
134
+ const bySite = new Map();
135
+ for (const entry of manifest) {
136
+ if (!entry?.site || !entry?.name) continue;
137
+ if (!bySite.has(entry.site)) bySite.set(entry.site, []);
138
+ bySite.get(entry.site).push(entry);
139
+ }
140
+
141
+ const findings = [];
142
+ let scannedSites = 0;
143
+ let scannedListings = 0;
144
+
145
+ for (const [site, entries] of bySite) {
146
+ // Only `access: 'read'` detail commands count — write commands like
147
+ // `instagram/post` or `instagram/note` create remote state, they don't
148
+ // fetch by id, so the listing→detail pairing rule doesn't apply.
149
+ const readDetail = entries.filter(
150
+ (e) => classify(e.name) === 'detail' && e.access === 'read',
151
+ );
152
+ const hasListing = entries.some((e) => classify(e.name) === 'listing');
153
+ if (!hasListing || readDetail.length === 0) continue;
154
+ scannedSites++;
155
+
156
+ for (const entry of entries) {
157
+ if (classify(entry.name) !== 'listing') continue;
158
+ scannedListings++;
159
+ const columns = Array.isArray(entry.columns) ? entry.columns : [];
160
+ if (!columns.some((col) => isIdColumn(col, readDetail))) {
161
+ findings.push({
162
+ site,
163
+ name: entry.name,
164
+ columns,
165
+ detail: readDetail.map((e) => e.name),
166
+ });
167
+ }
168
+ }
169
+ }
170
+
171
+ console.log(`Scanned ${scannedSites} site(s) with both listing and read-detail commands.`);
172
+ console.log(`Checked ${scannedListings} listing command(s).`);
173
+
174
+ if (findings.length === 0) {
175
+ console.log('OK — every listing carries an id-shaped column.');
176
+ return;
177
+ }
178
+
179
+ console.log('');
180
+ console.log(`Advisory: ${findings.length} listing(s) without a round-trippable id column.`);
181
+ console.log('Some of these are legitimate (topic strings, profile-attribute rows, UI-only');
182
+ console.log('sessions); others may be worth adding an id to. Use judgment, not a gate.');
183
+ console.log('');
184
+ for (const v of findings) {
185
+ console.log(` • ${v.site}/${v.name}`);
186
+ console.log(` columns: [${v.columns.join(', ')}]`);
187
+ console.log(` detail commands on this site: ${v.detail.join(', ')}`);
188
+ }
189
+ console.log('');
190
+ console.log('See docs/conventions/listing-detail-id-pairing.md for context and patterns.');
191
+ }
192
+
193
+ main();
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * check-silent-column-drop.mjs — CI gate for newly introduced table-output loss.
4
+ *
5
+ * This gate intentionally uses a baseline. The repo currently has known
6
+ * silent-column-drop findings, and blocking every existing violation would make
7
+ * the first CI adoption PR too large. The invariant enforced here is:
8
+ *
9
+ * no new silent-column-drop signatures beyond scripts/silent-column-drop-baseline.json
10
+ *
11
+ * When a follow-up sweep fixes existing violations, run:
12
+ *
13
+ * node scripts/check-silent-column-drop.mjs --update-baseline
14
+ */
15
+
16
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
17
+ import { dirname, resolve } from 'node:path';
18
+ import { fileURLToPath, pathToFileURL } from 'node:url';
19
+
20
+ const __dirname = dirname(fileURLToPath(import.meta.url));
21
+ const PROJECT_ROOT = resolve(__dirname, '..');
22
+ const DIST_AUDIT = resolve(PROJECT_ROOT, 'dist', 'src', 'convention-audit.js');
23
+ const BASELINE_PATH = resolve(__dirname, 'silent-column-drop-baseline.json');
24
+ const UPDATE = process.argv.includes('--update-baseline');
25
+
26
+ if (!existsSync(DIST_AUDIT)) {
27
+ console.error('dist/src/convention-audit.js not found. Run npm run build before this check.');
28
+ process.exit(1);
29
+ }
30
+
31
+ const { runConventionAudit } = await import(pathToFileURL(DIST_AUDIT).href);
32
+ const report = runConventionAudit({ projectRoot: PROJECT_ROOT });
33
+ const category = report.categories.find((item) => item.rule === 'silent-column-drop');
34
+ const current = sortRecords((category?.violations ?? []).map(toBaselineRecord));
35
+
36
+ if (UPDATE) {
37
+ writeFileSync(BASELINE_PATH, `${JSON.stringify(current, null, 2)}\n`);
38
+ console.log(`Updated ${relative(BASELINE_PATH)} with ${current.length} silent-column-drop baseline entr${current.length === 1 ? 'y' : 'ies'}.`);
39
+ process.exit(0);
40
+ }
41
+
42
+ if (!existsSync(BASELINE_PATH)) {
43
+ console.error(`${relative(BASELINE_PATH)} not found. Run node scripts/check-silent-column-drop.mjs --update-baseline.`);
44
+ process.exit(1);
45
+ }
46
+
47
+ const baseline = sortRecords(JSON.parse(readFileSync(BASELINE_PATH, 'utf-8')));
48
+ const baselineSignatures = new Set(baseline.map(signature));
49
+ const currentSignatures = new Set(current.map(signature));
50
+ const added = current.filter((record) => !baselineSignatures.has(signature(record)));
51
+ const resolved = baseline.filter((record) => !currentSignatures.has(signature(record)));
52
+
53
+ console.log(`Silent-column-drop gate: current=${current.length}, baseline=${baseline.length}, new=${added.length}, resolved=${resolved.length}`);
54
+
55
+ if (resolved.length > 0) {
56
+ console.log('');
57
+ console.log('Resolved baseline entries detected. Consider shrinking the baseline:');
58
+ for (const record of resolved) {
59
+ console.log(` - ${record.command} ${record.file} missing=[${record.missing.join(', ')}]`);
60
+ }
61
+ }
62
+
63
+ if (added.length === 0) {
64
+ console.log('OK - no new silent-column-drop violations.');
65
+ process.exit(0);
66
+ }
67
+
68
+ console.log('');
69
+ console.log('New silent-column-drop violations:');
70
+ for (const record of added) {
71
+ console.log(` - ${record.command} ${record.file} missing=[${record.missing.join(', ')}]`);
72
+ }
73
+ console.log('');
74
+ console.log('Fix the adapter columns, or if this is an intentional baseline adoption, run:');
75
+ console.log(' node scripts/check-silent-column-drop.mjs --update-baseline');
76
+ process.exit(1);
77
+
78
+ function toBaselineRecord(violation) {
79
+ const missing = Array.isArray(violation.details?.missing)
80
+ ? violation.details.missing.map(String).sort()
81
+ : [];
82
+ return {
83
+ command: String(violation.command ?? ''),
84
+ file: String(violation.file ?? ''),
85
+ missing,
86
+ };
87
+ }
88
+
89
+ function signature(record) {
90
+ return `${record.command}\0${record.file}\0${record.missing.join('\0')}`;
91
+ }
92
+
93
+ function sortRecords(records) {
94
+ return records
95
+ .map((record) => ({
96
+ command: String(record.command),
97
+ file: String(record.file),
98
+ missing: Array.isArray(record.missing) ? record.missing.map(String).sort() : [],
99
+ }))
100
+ .sort((a, b) => signature(a).localeCompare(signature(b)));
101
+ }
102
+
103
+ function relative(file) {
104
+ return file.replace(`${PROJECT_ROOT}/`, '');
105
+ }