publishport-opencli 1.0.19 → 1.0.21

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 (1042) hide show
  1. package/cli-manifest.json +35 -0
  2. package/clis/12306/me.js +2 -2
  3. package/clis/12306/orders.js +3 -3
  4. package/clis/12306/passengers.js +3 -3
  5. package/clis/12306/price.js +1 -1
  6. package/clis/12306/stations.js +1 -1
  7. package/clis/12306/train.js +1 -1
  8. package/clis/12306/trains.js +1 -1
  9. package/clis/12306/utils.js +1 -1
  10. package/clis/1688/download.js +1 -1
  11. package/clis/1688/item.js +4 -4
  12. package/clis/1688/search.js +4 -4
  13. package/clis/1688/store.js +4 -4
  14. package/clis/1point3acres/forum.js +1 -1
  15. package/clis/1point3acres/forums.js +1 -1
  16. package/clis/1point3acres/notifications.js +1 -1
  17. package/clis/1point3acres/search.js +1 -1
  18. package/clis/1point3acres/thread.js +2 -2
  19. package/clis/1point3acres/user.js +1 -1
  20. package/clis/1point3acres/utils.js +2 -2
  21. package/clis/36kr/article.js +2 -2
  22. package/clis/36kr/hot.js +2 -2
  23. package/clis/36kr/news.js +1 -1
  24. package/clis/36kr/search.js +2 -2
  25. package/clis/51job/company.js +2 -2
  26. package/clis/51job/detail.js +2 -2
  27. package/clis/51job/hot.js +1 -1
  28. package/clis/51job/search.js +1 -1
  29. package/clis/51job/utils.js +7 -7
  30. package/clis/_atlassian/shared.js +9 -9
  31. package/clis/_shared/article/auth.js +4 -4
  32. package/clis/_shared/article/douban-md2draft.js +4 -4
  33. package/clis/_shared/article/format.js +1 -1
  34. package/clis/_shared/article/images.js +7 -7
  35. package/clis/_shared/article/login.js +1 -1
  36. package/clis/_shared/article/publish.js +11 -11
  37. package/clis/_shared/common.js +1 -1
  38. package/clis/_shared/content-guard.js +1 -1
  39. package/clis/_shared/desktop-commands.js +1 -1
  40. package/clis/_shared/file-inject.js +12 -12
  41. package/clis/_shared/self-hosted-sites.js +2 -2
  42. package/clis/_shared/site-auth.js +1 -1
  43. package/clis/_shared/token-auth.js +2 -2
  44. package/clis/_shared/video-publish.js +9 -9
  45. package/clis/amazon/offer.js +3 -3
  46. package/clis/amazon/product.js +5 -5
  47. package/clis/amazon/shared.js +6 -6
  48. package/clis/antigravity/_actions.js +13 -13
  49. package/clis/antigravity/audit-extras.js +10 -10
  50. package/clis/antigravity/delete.js +1 -1
  51. package/clis/antigravity/model.js +6 -6
  52. package/clis/antigravity/new.js +2 -2
  53. package/clis/antigravity/read.js +2 -2
  54. package/clis/antigravity/rename.js +1 -1
  55. package/clis/antigravity/send.js +3 -3
  56. package/clis/antigravity/serve.js +17 -17
  57. package/clis/antigravity/storage.js +6 -6
  58. package/clis/antigravity/watch.js +2 -2
  59. package/clis/apple-podcasts/episodes.js +1 -1
  60. package/clis/apple-podcasts/top.js +1 -1
  61. package/clis/apple-podcasts/utils.js +1 -1
  62. package/clis/archive/item.js +1 -1
  63. package/clis/archive/search.js +1 -1
  64. package/clis/archive/snapshots.js +1 -1
  65. package/clis/archive/wayback.js +1 -1
  66. package/clis/arxiv/author.js +1 -1
  67. package/clis/arxiv/utils.js +1 -1
  68. package/clis/autohome/brand.js +1 -1
  69. package/clis/autohome/score.js +1 -1
  70. package/clis/autohome/utils.js +1 -1
  71. package/clis/baijiahao/article.js +1 -1
  72. package/clis/baijiahao/lists.js +1 -1
  73. package/clis/baijiahao/login.js +1 -1
  74. package/clis/baijiahao/publish.js +9 -9
  75. package/clis/baijiahao/stats.js +1 -1
  76. package/clis/baijiahao/whoami.js +1 -1
  77. package/clis/band/bands.js +2 -2
  78. package/clis/band/mentions.js +2 -2
  79. package/clis/band/post.js +4 -4
  80. package/clis/band/posts.js +3 -3
  81. package/clis/barchart/flow.js +3 -3
  82. package/clis/barchart/greeks.js +2 -2
  83. package/clis/barchart/quote.js +3 -3
  84. package/clis/bbc/news.js +1 -1
  85. package/clis/bbc/topic.js +1 -1
  86. package/clis/bbc/utils.js +1 -1
  87. package/clis/bilibili/article.js +1 -1
  88. package/clis/bilibili/categories.js +1 -1
  89. package/clis/bilibili/coin.js +1 -1
  90. package/clis/bilibili/comment-del.js +1 -1
  91. package/clis/bilibili/comment-like.js +1 -1
  92. package/clis/bilibili/comment.js +1 -1
  93. package/clis/bilibili/comments.js +1 -1
  94. package/clis/bilibili/dm-list.js +1 -1
  95. package/clis/bilibili/dm-read.js +1 -1
  96. package/clis/bilibili/dm-send.js +1 -1
  97. package/clis/bilibili/download.js +2 -2
  98. package/clis/bilibili/drafts.js +1 -1
  99. package/clis/bilibili/dynamic-post.js +3 -3
  100. package/clis/bilibili/favorite-add.js +1 -1
  101. package/clis/bilibili/favorite.js +1 -1
  102. package/clis/bilibili/feed.js +2 -2
  103. package/clis/bilibili/follow.js +1 -1
  104. package/clis/bilibili/following.js +1 -1
  105. package/clis/bilibili/like.js +1 -1
  106. package/clis/bilibili/partitions.js +1 -1
  107. package/clis/bilibili/stats.js +1 -1
  108. package/clis/bilibili/subtitle.js +3 -3
  109. package/clis/bilibili/summary.js +1 -1
  110. package/clis/bilibili/topics.js +1 -1
  111. package/clis/bilibili/unfollow.js +1 -1
  112. package/clis/bilibili/upload.js +1 -1
  113. package/clis/bilibili/utils.js +10 -10
  114. package/clis/bilibili/video-drafts.js +1 -1
  115. package/clis/bilibili/video.js +1 -1
  116. package/clis/bloomberg/businessweek.js +4 -4
  117. package/clis/bloomberg/news.js +2 -2
  118. package/clis/bloomberg/utils.js +13 -13
  119. package/clis/bluesky/post.js +1 -1
  120. package/clis/bluesky/shared.js +11 -11
  121. package/clis/bluesky/whoami.js +1 -1
  122. package/clis/booking/search.js +2 -2
  123. package/clis/boss/accept.js +1 -1
  124. package/clis/boss/applied.js +1 -1
  125. package/clis/boss/auth.js +1 -1
  126. package/clis/boss/batchgreet.js +1 -1
  127. package/clis/boss/bossinfo.js +1 -1
  128. package/clis/boss/chatlist.js +1 -1
  129. package/clis/boss/chatmsg.js +1 -1
  130. package/clis/boss/cities.js +1 -1
  131. package/clis/boss/detail.js +1 -1
  132. package/clis/boss/exchange.js +1 -1
  133. package/clis/boss/greet.js +1 -1
  134. package/clis/boss/interviews.js +1 -1
  135. package/clis/boss/invite.js +1 -1
  136. package/clis/boss/joblist.js +1 -1
  137. package/clis/boss/mark.js +1 -1
  138. package/clis/boss/me.js +2 -2
  139. package/clis/boss/recommend.js +1 -1
  140. package/clis/boss/resumedelete.js +1 -1
  141. package/clis/boss/resumelist.js +1 -1
  142. package/clis/boss/resumeupload.js +11 -11
  143. package/clis/boss/search.js +1 -1
  144. package/clis/boss/send.js +1 -1
  145. package/clis/boss/sendresume.js +1 -1
  146. package/clis/boss/stats.js +1 -1
  147. package/clis/boss/unread.js +1 -1
  148. package/clis/boss/utils.js +13 -13
  149. package/clis/chaoxing/assignments.js +1 -1
  150. package/clis/chaoxing/exams.js +1 -1
  151. package/clis/chaoxing/utils.js +9 -9
  152. package/clis/chatgpt/ask.js +1 -1
  153. package/clis/chatgpt/auth.js +2 -2
  154. package/clis/chatgpt/detail.js +1 -1
  155. package/clis/chatgpt/image.js +1 -1
  156. package/clis/chatgpt/read.js +1 -1
  157. package/clis/chatgpt/send.js +1 -1
  158. package/clis/chatgpt/utils.js +59 -59
  159. package/clis/chatgpt-app/ask.js +1 -1
  160. package/clis/chatgpt-app/send.js +1 -1
  161. package/clis/chatwise/model.js +6 -6
  162. package/clis/chess/analyze.js +1 -1
  163. package/clis/chess/game.js +1 -1
  164. package/clis/chess/games.js +1 -1
  165. package/clis/chess/stats.js +1 -1
  166. package/clis/chess/utils.js +1 -1
  167. package/clis/claude/ask.js +2 -2
  168. package/clis/claude/detail.js +1 -1
  169. package/clis/claude/new.js +1 -1
  170. package/clis/claude/read.js +1 -1
  171. package/clis/claude/send.js +1 -1
  172. package/clis/claude/utils.js +23 -23
  173. package/clis/cnblogs/article.js +1 -1
  174. package/clis/cnblogs/login.js +1 -1
  175. package/clis/cnblogs/stats.js +7 -7
  176. package/clis/cnblogs/whoami.js +1 -1
  177. package/clis/codex/_actions.js +3 -3
  178. package/clis/codex/archive.js +1 -1
  179. package/clis/codex/ask.js +6 -6
  180. package/clis/codex/model.js +8 -8
  181. package/clis/codex/pin.js +1 -1
  182. package/clis/codex/rename.js +4 -4
  183. package/clis/codex/send.js +3 -3
  184. package/clis/codex/sidebar.js +1 -1
  185. package/clis/coingecko/categories.js +1 -1
  186. package/clis/coingecko/coin.js +1 -1
  187. package/clis/coingecko/derivatives.js +1 -1
  188. package/clis/coingecko/exchanges.js +1 -1
  189. package/clis/coingecko/global.js +1 -1
  190. package/clis/coingecko/trending.js +1 -1
  191. package/clis/confluence/search.js +1 -1
  192. package/clis/coupang/product.js +3 -3
  193. package/clis/coupang/utils.js +1 -1
  194. package/clis/crates/crate.js +1 -1
  195. package/clis/crates/search.js +1 -1
  196. package/clis/crates/utils.js +1 -1
  197. package/clis/csdn/article.js +13 -13
  198. package/clis/csdn/columns.js +1 -1
  199. package/clis/csdn/login.js +1 -1
  200. package/clis/csdn/stats.js +4 -4
  201. package/clis/csdn/whoami.js +1 -1
  202. package/clis/cto51/article.js +1 -1
  203. package/clis/cto51/whoami.js +1 -1
  204. package/clis/ctrip/flight.js +2 -2
  205. package/clis/ctrip/hotel-search.js +3 -3
  206. package/clis/ctrip/hotel-suggest.js +1 -1
  207. package/clis/ctrip/search.js +1 -1
  208. package/clis/ctrip/utils.js +6 -6
  209. package/clis/cursor/ask.js +5 -5
  210. package/clis/cursor/composer.js +2 -2
  211. package/clis/cursor/model.js +4 -4
  212. package/clis/cursor/send.js +2 -2
  213. package/clis/dblp/author.js +1 -1
  214. package/clis/dblp/paper.js +1 -1
  215. package/clis/dblp/search.js +1 -1
  216. package/clis/dblp/utils.js +1 -1
  217. package/clis/dblp/venue.js +1 -1
  218. package/clis/deepseek/ask.js +1 -1
  219. package/clis/deepseek/auth.js +2 -2
  220. package/clis/deepseek/detail.js +1 -1
  221. package/clis/deepseek/new.js +1 -1
  222. package/clis/deepseek/read.js +1 -1
  223. package/clis/deepseek/send.js +7 -7
  224. package/clis/deepseek/utils.js +25 -25
  225. package/clis/defillama/protocol.js +1 -1
  226. package/clis/defillama/protocols.js +1 -1
  227. package/clis/defillama/utils.js +1 -1
  228. package/clis/devto/auth.js +2 -2
  229. package/clis/devto/latest.js +1 -1
  230. package/clis/devto/publish.js +5 -5
  231. package/clis/devto/read.js +2 -2
  232. package/clis/devto/stats.js +3 -3
  233. package/clis/dianping/auth.js +2 -2
  234. package/clis/dianping/cityResolver.js +2 -2
  235. package/clis/dianping/search.js +1 -1
  236. package/clis/dianping/shop.js +1 -1
  237. package/clis/dianping/utils.js +1 -1
  238. package/clis/discord-app/delete.js +3 -3
  239. package/clis/discord-app/read.js +1 -1
  240. package/clis/discord-app/thread-read.js +1 -1
  241. package/clis/discord-web/auth.js +2 -2
  242. package/clis/discord-web/send.js +5 -5
  243. package/clis/dockerhub/image.js +1 -1
  244. package/clis/dockerhub/search.js +1 -1
  245. package/clis/dockerhub/utils.js +1 -1
  246. package/clis/dongchedi/koubei.js +1 -1
  247. package/clis/dongchedi/models.js +1 -1
  248. package/clis/dongchedi/score.js +1 -1
  249. package/clis/dongchedi/search.js +1 -1
  250. package/clis/dongchedi/series.js +1 -1
  251. package/clis/dongchedi/specs.js +1 -1
  252. package/clis/dongchedi/utils.js +1 -1
  253. package/clis/douban/article.js +3 -3
  254. package/clis/douban/auth.js +2 -2
  255. package/clis/douban/download.js +1 -1
  256. package/clis/douban/utils.js +23 -23
  257. package/clis/doubao/auth.js +3 -3
  258. package/clis/doubao/utils.js +39 -39
  259. package/clis/doubao-app/ask.js +1 -1
  260. package/clis/doubao-app/utils.js +4 -4
  261. package/clis/douyin/_shared/browser-fetch.js +7 -7
  262. package/clis/douyin/_shared/draft-cache.js +1 -1
  263. package/clis/douyin/_shared/imagex-upload.js +1 -1
  264. package/clis/douyin/_shared/sts2.js +1 -1
  265. package/clis/douyin/_shared/text-extra.js +1 -1
  266. package/clis/douyin/_shared/tos-upload.js +4 -4
  267. package/clis/douyin/_shared/transcode.js +1 -1
  268. package/clis/douyin/_shared/vod-upload.js +4 -4
  269. package/clis/douyin/draft.js +18 -18
  270. package/clis/douyin/drafts.js +1 -1
  271. package/clis/douyin/publish-image.js +12 -12
  272. package/clis/douyin/publish.js +9 -9
  273. package/clis/douyin/search.js +3 -3
  274. package/clis/douyin/videos.js +1 -1
  275. package/clis/eastmoney/_secid.js +1 -1
  276. package/clis/eastmoney/announcement.js +1 -1
  277. package/clis/eastmoney/article.js +1 -1
  278. package/clis/eastmoney/convertible.js +1 -1
  279. package/clis/eastmoney/etf.js +1 -1
  280. package/clis/eastmoney/holders.js +1 -1
  281. package/clis/eastmoney/index-board.js +1 -1
  282. package/clis/eastmoney/kline.js +1 -1
  283. package/clis/eastmoney/kuaixun.js +1 -1
  284. package/clis/eastmoney/longhu.js +1 -1
  285. package/clis/eastmoney/money-flow.js +1 -1
  286. package/clis/eastmoney/northbound.js +1 -1
  287. package/clis/eastmoney/quote.js +1 -1
  288. package/clis/eastmoney/rank.js +1 -1
  289. package/clis/eastmoney/sectors.js +1 -1
  290. package/clis/endoflife/product.js +1 -1
  291. package/clis/endoflife/utils.js +1 -1
  292. package/clis/facebook/comment.js +8 -8
  293. package/clis/facebook/feed.js +4 -4
  294. package/clis/facebook/like.js +5 -5
  295. package/clis/facebook/notifications.js +3 -3
  296. package/clis/facebook/post.js +11 -11
  297. package/clis/facebook/search.js +3 -3
  298. package/clis/flathub/app.js +1 -1
  299. package/clis/flathub/search.js +1 -1
  300. package/clis/flathub/utils.js +1 -1
  301. package/clis/flomo/memos.js +1 -1
  302. package/clis/gemini/deep-research-result.js +4 -4
  303. package/clis/gemini/deep-research.js +1 -1
  304. package/clis/gemini/detail.js +1 -1
  305. package/clis/gemini/history.js +1 -1
  306. package/clis/gemini/image.js +2 -2
  307. package/clis/gemini/status.js +1 -1
  308. package/clis/gemini/utils.js +43 -43
  309. package/clis/geogebra/hexagon.js +1 -1
  310. package/clis/geogebra/info.js +3 -3
  311. package/clis/geogebra/triangle.js +1 -1
  312. package/clis/geogebra/utils.js +11 -11
  313. package/clis/ghost/login.js +1 -1
  314. package/clis/ghost/shared.js +2 -2
  315. package/clis/gitee/auth.js +2 -2
  316. package/clis/github-trending/repos.js +1 -1
  317. package/clis/google/news.js +1 -1
  318. package/clis/google/search.js +2 -2
  319. package/clis/google/suggest.js +1 -1
  320. package/clis/google/trends.js +1 -1
  321. package/clis/google/utils.js +1 -1
  322. package/clis/goproxy/module.js +1 -1
  323. package/clis/goproxy/utils.js +1 -1
  324. package/clis/goproxy/versions.js +1 -1
  325. package/clis/gov-policy/recent.js +2 -2
  326. package/clis/gov-policy/search.js +2 -2
  327. package/clis/grok/ask.js +1 -1
  328. package/clis/grok/detail.js +1 -1
  329. package/clis/grok/image.js +8 -8
  330. package/clis/grok/pin.js +1 -1
  331. package/clis/grok/send.js +1 -1
  332. package/clis/grok/status.js +1 -1
  333. package/clis/grok/utils.js +21 -21
  334. package/clis/guazi/browse.js +1 -1
  335. package/clis/guazi/car.js +1 -1
  336. package/clis/guazi/utils.js +1 -1
  337. package/clis/hackernews/auth.js +2 -2
  338. package/clis/hackernews/comment.js +8 -8
  339. package/clis/hackernews/read.js +7 -7
  340. package/clis/hackernews/submit.js +7 -7
  341. package/clis/hashnode/auth.js +3 -3
  342. package/clis/hashnode/publish.js +14 -14
  343. package/clis/hf/auth.js +2 -2
  344. package/clis/hf/models.js +1 -1
  345. package/clis/hf/paper.js +1 -1
  346. package/clis/hf/spaces.js +1 -1
  347. package/clis/hf/top.js +1 -1
  348. package/clis/homebrew/cask.js +1 -1
  349. package/clis/homebrew/formula.js +1 -1
  350. package/clis/homebrew/popular.js +1 -1
  351. package/clis/homebrew/utils.js +1 -1
  352. package/clis/huodongxing/events.js +1 -1
  353. package/clis/hupu/detail.js +4 -4
  354. package/clis/hupu/hot.js +3 -3
  355. package/clis/hupu/reply.js +1 -1
  356. package/clis/hupu/search.js +1 -1
  357. package/clis/hupu/unlike.js +1 -1
  358. package/clis/hupu/utils.js +10 -10
  359. package/clis/imdb/person.js +2 -2
  360. package/clis/imdb/reviews.js +3 -3
  361. package/clis/imdb/search.js +2 -2
  362. package/clis/imdb/title.js +1 -1
  363. package/clis/imdb/top.js +1 -1
  364. package/clis/imdb/trending.js +1 -1
  365. package/clis/imdb/utils.js +13 -13
  366. package/clis/imooc/article.js +6 -6
  367. package/clis/imooc/login.js +1 -1
  368. package/clis/imooc/whoami.js +1 -1
  369. package/clis/indeed/job.js +2 -2
  370. package/clis/indeed/search.js +2 -2
  371. package/clis/indeed/utils.js +1 -1
  372. package/clis/infoq/article.js +2 -2
  373. package/clis/infoq/login.js +1 -1
  374. package/clis/infoq/whoami.js +1 -1
  375. package/clis/instagram/_shared/private-publish.js +4 -4
  376. package/clis/instagram/_shared/protocol-capture.js +9 -9
  377. package/clis/instagram/detail.js +3 -3
  378. package/clis/instagram/post.js +25 -25
  379. package/clis/instagram/reel.js +18 -18
  380. package/clis/instagram/story.js +4 -4
  381. package/clis/instagram/user.js +2 -2
  382. package/clis/jd/item.js +65 -65
  383. package/clis/jianshu/article.js +1 -1
  384. package/clis/jianshu/login.js +1 -1
  385. package/clis/jianshu/notebooks.js +1 -1
  386. package/clis/jianshu/whoami.js +1 -1
  387. package/clis/jianyu/search.js +6 -6
  388. package/clis/jianyu/shared/procurement-contract.js +1 -1
  389. package/clis/jike/api.js +6 -6
  390. package/clis/jike/auth.js +3 -3
  391. package/clis/jike/comment.js +1 -1
  392. package/clis/jike/create.js +6 -6
  393. package/clis/jike/feed.js +3 -3
  394. package/clis/jike/like.js +1 -1
  395. package/clis/jike/notifications.js +3 -3
  396. package/clis/jike/repost.js +13 -13
  397. package/clis/jike/search.js +3 -3
  398. package/clis/jimeng/auth.js +2 -2
  399. package/clis/jimeng/generate.js +10 -10
  400. package/clis/jira/shared.js +1 -1
  401. package/clis/juejin/article.js +4 -4
  402. package/clis/juejin/categories.js +1 -1
  403. package/clis/juejin/hot.js +1 -1
  404. package/clis/juejin/login.js +1 -1
  405. package/clis/juejin/recommend.js +1 -1
  406. package/clis/juejin/stats.js +3 -3
  407. package/clis/juejin/tags.js +1 -1
  408. package/clis/juejin/utils.js +1 -1
  409. package/clis/juejin/whoami.js +1 -1
  410. package/clis/ke/utils.js +4 -4
  411. package/clis/kimi/_utils.js +7 -7
  412. package/clis/kimi/audit-extras.js +14 -14
  413. package/clis/kimi/auth.js +3 -3
  414. package/clis/kimi/chat.js +15 -15
  415. package/clis/kimi/storage.js +5 -5
  416. package/clis/kimi/ui.js +13 -13
  417. package/clis/kimi/usage.js +3 -3
  418. package/clis/kuaishou/auth.js +1 -1
  419. package/clis/kuaishou/publish.js +6 -6
  420. package/clis/lesswrong/_helpers.js +5 -5
  421. package/clis/lesswrong/comments.js +5 -5
  422. package/clis/lichess/top.js +1 -1
  423. package/clis/lichess/user.js +1 -1
  424. package/clis/lichess/utils.js +1 -1
  425. package/clis/linkedin/comment.js +1 -1
  426. package/clis/linkedin/connect.js +11 -11
  427. package/clis/linkedin/create.js +5 -5
  428. package/clis/linkedin/follow.js +1 -1
  429. package/clis/linkedin/inbox.js +1 -1
  430. package/clis/linkedin/job-detail.js +3 -3
  431. package/clis/linkedin/like.js +1 -1
  432. package/clis/linkedin/notifications.js +1 -1
  433. package/clis/linkedin/people-search.js +1 -1
  434. package/clis/linkedin/post-comments.js +1 -1
  435. package/clis/linkedin/post-detail.js +1 -1
  436. package/clis/linkedin/profile-analytics.js +1 -1
  437. package/clis/linkedin/profile-api.js +13 -13
  438. package/clis/linkedin/profile-experience.js +1 -1
  439. package/clis/linkedin/profile-projects.js +1 -1
  440. package/clis/linkedin/profile-read.js +3 -3
  441. package/clis/linkedin/reply.js +1 -1
  442. package/clis/linkedin/repost.js +1 -1
  443. package/clis/linkedin/safe-send.js +8 -8
  444. package/clis/linkedin/salesnav-inbox.js +5 -5
  445. package/clis/linkedin/salesnav-message.js +3 -3
  446. package/clis/linkedin/salesnav-search.js +4 -4
  447. package/clis/linkedin/salesnav-thread.js +1 -1
  448. package/clis/linkedin/search-api.js +3 -3
  449. package/clis/linkedin/search.js +8 -8
  450. package/clis/linkedin/social-api.js +31 -31
  451. package/clis/linkedin/timeline.js +3 -3
  452. package/clis/linkedin-learning/search.js +2 -2
  453. package/clis/linkedin-learning/trending.js +2 -2
  454. package/clis/linux-do/feed.js +4 -4
  455. package/clis/linux-do/topic-content.js +8 -8
  456. package/clis/lobsters/domain.js +1 -1
  457. package/clis/lobsters/read.js +7 -7
  458. package/clis/maimai/auth.js +2 -2
  459. package/clis/maimai/search-talents.js +4 -4
  460. package/clis/manus/_utils.js +1 -1
  461. package/clis/mastodon/login.js +1 -1
  462. package/clis/mastodon/post.js +1 -1
  463. package/clis/mastodon/shared.js +12 -12
  464. package/clis/mastodon/whoami.js +1 -1
  465. package/clis/maven/artifact.js +1 -1
  466. package/clis/maven/search.js +1 -1
  467. package/clis/maven/utils.js +1 -1
  468. package/clis/mdn/search.js +1 -1
  469. package/clis/medium/article.js +5 -5
  470. package/clis/medium/login.js +1 -1
  471. package/clis/medium/stats.js +3 -3
  472. package/clis/medium/tag.js +1 -1
  473. package/clis/medium/whoami.js +1 -1
  474. package/clis/mubu/notes.js +1 -1
  475. package/clis/mubu/utils.js +15 -15
  476. package/clis/note/auth.js +2 -2
  477. package/clis/note/note-utils.js +2 -2
  478. package/clis/note/publish.js +8 -8
  479. package/clis/notebooklm/add-source.js +8 -8
  480. package/clis/notebooklm/create.js +1 -1
  481. package/clis/notebooklm/generate-slides.js +1 -1
  482. package/clis/notebooklm/notes-get.js +1 -1
  483. package/clis/notebooklm/rpc.js +8 -8
  484. package/clis/notebooklm/source-fulltext.js +1 -1
  485. package/clis/notebooklm/utils.js +10 -10
  486. package/clis/nowcoder/auth.js +2 -2
  487. package/clis/nowcoder/comment.js +1 -1
  488. package/clis/nowcoder/comments.js +1 -1
  489. package/clis/nowcoder/dm-list.js +1 -1
  490. package/clis/nowcoder/dm-read.js +1 -1
  491. package/clis/nowcoder/dm-send.js +1 -1
  492. package/clis/nowcoder/drafts.js +1 -1
  493. package/clis/nowcoder/inbox.js +1 -1
  494. package/clis/nowcoder/like.js +1 -1
  495. package/clis/nowcoder/my.js +1 -1
  496. package/clis/nowcoder/post.js +1 -1
  497. package/clis/nowcoder/utils.js +13 -13
  498. package/clis/npm/downloads.js +1 -1
  499. package/clis/npm/package.js +1 -1
  500. package/clis/npm/search.js +1 -1
  501. package/clis/npm/utils.js +1 -1
  502. package/clis/nuget/package.js +1 -1
  503. package/clis/nuget/search.js +1 -1
  504. package/clis/nuget/utils.js +1 -1
  505. package/clis/nvd/cve.js +1 -1
  506. package/clis/oeis/search.js +1 -1
  507. package/clis/oeis/sequence.js +1 -1
  508. package/clis/oeis/utils.js +1 -1
  509. package/clis/ones/common.js +6 -6
  510. package/clis/ones/enrich-tasks.js +1 -1
  511. package/clis/ones/my-tasks.js +1 -1
  512. package/clis/ones/resolve-labels.js +1 -1
  513. package/clis/ones/task-helpers.js +1 -1
  514. package/clis/ones/task.js +1 -1
  515. package/clis/ones/worklog.js +7 -7
  516. package/clis/openalex/search.js +1 -1
  517. package/clis/openalex/utils.js +1 -1
  518. package/clis/openalex/work.js +1 -1
  519. package/clis/openfda/drug-label.js +1 -1
  520. package/clis/openfda/food-recall.js +1 -1
  521. package/clis/openfda/utils.js +1 -1
  522. package/clis/openreview/author.js +1 -1
  523. package/clis/openreview/paper.js +1 -1
  524. package/clis/openreview/reviews.js +3 -3
  525. package/clis/openreview/search.js +1 -1
  526. package/clis/openreview/utils.js +1 -1
  527. package/clis/openreview/venue.js +1 -1
  528. package/clis/oschina/article.js +1 -1
  529. package/clis/oschina/catalogs.js +1 -1
  530. package/clis/oschina/login.js +1 -1
  531. package/clis/oschina/stats.js +6 -6
  532. package/clis/oschina/whoami.js +1 -1
  533. package/clis/osv/query.js +1 -1
  534. package/clis/osv/utils.js +1 -1
  535. package/clis/osv/vulnerability.js +1 -1
  536. package/clis/packagist/package.js +1 -1
  537. package/clis/packagist/search.js +1 -1
  538. package/clis/packagist/utils.js +1 -1
  539. package/clis/pinterest/api.js +1 -1
  540. package/clis/pinterest/auth.js +1 -1
  541. package/clis/pinterest/boards.js +1 -1
  542. package/clis/pinterest/client.js +6 -6
  543. package/clis/pinterest/publish.js +5 -5
  544. package/clis/pixiv/auth.js +2 -2
  545. package/clis/pixiv/download.js +1 -1
  546. package/clis/pixiv/illusts.js +1 -1
  547. package/clis/pixiv/search.js +1 -1
  548. package/clis/pixiv/utils.js +3 -3
  549. package/clis/powerchina/auth.js +2 -2
  550. package/clis/powerchina/search.js +1 -1
  551. package/clis/producthunt/browse.js +2 -2
  552. package/clis/producthunt/hot.js +2 -2
  553. package/clis/producthunt/posts.js +1 -1
  554. package/clis/producthunt/today.js +1 -1
  555. package/clis/producthunt/utils.js +1 -1
  556. package/clis/pypi/downloads.js +1 -1
  557. package/clis/pypi/package.js +1 -1
  558. package/clis/pypi/utils.js +1 -1
  559. package/clis/qiita/auth.js +1 -1
  560. package/clis/qiita/gql.js +6 -6
  561. package/clis/qiita/publish.js +4 -4
  562. package/clis/qiita/stats.js +4 -4
  563. package/clis/qoder/_utils.js +16 -16
  564. package/clis/qoder/composer.js +1 -1
  565. package/clis/qoder/quest.js +1 -1
  566. package/clis/qoder/ui.js +14 -14
  567. package/clis/quark/auth.js +2 -2
  568. package/clis/quark/utils.js +2 -2
  569. package/clis/quora/answer-comments.js +3 -3
  570. package/clis/quora/create-answer.js +4 -4
  571. package/clis/quora/create-question.js +3 -3
  572. package/clis/quora/shared.js +17 -17
  573. package/clis/quora/whoami.js +1 -1
  574. package/clis/qwen/ask.js +1 -1
  575. package/clis/qwen/auth.js +3 -3
  576. package/clis/qwen/detail.js +1 -1
  577. package/clis/qwen/image.js +5 -5
  578. package/clis/qwen/status.js +1 -1
  579. package/clis/qwen/utils.js +16 -16
  580. package/clis/reddit/home.js +3 -3
  581. package/clis/reddit/read.js +10 -10
  582. package/clis/reddit/reply.js +4 -4
  583. package/clis/reddit/submit.js +11 -11
  584. package/clis/reddit/subreddit-info.js +3 -3
  585. package/clis/reddit/subscribed.js +4 -4
  586. package/clis/reddit/whoami.js +2 -2
  587. package/clis/rednote/comments.js +1 -1
  588. package/clis/rednote/download.js +1 -1
  589. package/clis/rednote/feed.js +1 -1
  590. package/clis/rednote/note.js +1 -1
  591. package/clis/rednote/notifications.js +2 -2
  592. package/clis/rednote/search.js +2 -2
  593. package/clis/rest-countries/country.js +1 -1
  594. package/clis/rest-countries/region.js +1 -1
  595. package/clis/rest-countries/utils.js +1 -1
  596. package/clis/reuters/article-detail.js +1 -1
  597. package/clis/reuters/auth.js +3 -3
  598. package/clis/reuters/search.js +1 -1
  599. package/clis/reuters/utils.js +4 -4
  600. package/clis/rfc/rfc.js +1 -1
  601. package/clis/rfc/utils.js +1 -1
  602. package/clis/rubygems/gem.js +1 -1
  603. package/clis/rubygems/search.js +1 -1
  604. package/clis/rubygems/utils.js +1 -1
  605. package/clis/segmentfault/article.js +3 -3
  606. package/clis/segmentfault/channels.js +1 -1
  607. package/clis/segmentfault/login.js +1 -1
  608. package/clis/segmentfault/stats.js +4 -4
  609. package/clis/segmentfault/tags.js +1 -1
  610. package/clis/segmentfault/whoami.js +1 -1
  611. package/clis/semanticscholar/citations.js +1 -1
  612. package/clis/semanticscholar/paper.js +1 -1
  613. package/clis/semanticscholar/recommendations.js +1 -1
  614. package/clis/semanticscholar/search.js +1 -1
  615. package/clis/semanticscholar/utils.js +1 -1
  616. package/clis/sinafinance/news.js +1 -1
  617. package/clis/sinafinance/stock-rank.js +1 -1
  618. package/clis/sinafinance/stock.js +1 -1
  619. package/clis/slock/attachment-download.js +1 -1
  620. package/clis/slock/attachment-upload.js +7 -7
  621. package/clis/slock/attachment-url.js +1 -1
  622. package/clis/slock/auth-verify.js +1 -1
  623. package/clis/slock/bookmark-add.js +1 -1
  624. package/clis/slock/bookmark-remove.js +1 -1
  625. package/clis/slock/channel-action.js +1 -1
  626. package/clis/slock/channel-create.js +1 -1
  627. package/clis/slock/channel-files.js +1 -1
  628. package/clis/slock/channel-list.js +1 -1
  629. package/clis/slock/channel-mark.js +1 -1
  630. package/clis/slock/channel-members.js +1 -1
  631. package/clis/slock/channel-unarchive.js +1 -1
  632. package/clis/slock/dm-list.js +1 -1
  633. package/clis/slock/errors.js +1 -1
  634. package/clis/slock/in-page.js +28 -28
  635. package/clis/slock/inbox-done.js +5 -5
  636. package/clis/slock/inbox.js +1 -1
  637. package/clis/slock/message-read.js +22 -22
  638. package/clis/slock/message-search.js +10 -10
  639. package/clis/slock/message-send.js +25 -25
  640. package/clis/slock/reaction-add.js +1 -1
  641. package/clis/slock/reaction-remove.js +1 -1
  642. package/clis/slock/resolve.js +1 -1
  643. package/clis/slock/server-list.js +2 -2
  644. package/clis/slock/task-claim.js +4 -4
  645. package/clis/slock/task-convert.js +13 -13
  646. package/clis/slock/task-create.js +1 -1
  647. package/clis/slock/task-delete.js +5 -5
  648. package/clis/slock/task-get.js +5 -5
  649. package/clis/slock/task-list-server.js +4 -4
  650. package/clis/slock/task-list.js +5 -5
  651. package/clis/slock/task-status.js +3 -3
  652. package/clis/slock/task-unclaim.js +3 -3
  653. package/clis/slock/thread-follow.js +1 -1
  654. package/clis/slock/thread-state.js +1 -1
  655. package/clis/slock/unread-summary.js +5 -5
  656. package/clis/slock/whoami.js +1 -1
  657. package/clis/smzdm/search.js +3 -3
  658. package/clis/sohu/article.js +1 -1
  659. package/clis/sohu/attributes.js +1 -1
  660. package/clis/sohu/categories.js +1 -1
  661. package/clis/sohu/channels.js +1 -1
  662. package/clis/sohu/columns.js +1 -1
  663. package/clis/sohu/login.js +1 -1
  664. package/clis/sohu/stats.js +3 -3
  665. package/clis/sohu/topics.js +1 -1
  666. package/clis/sohu/whoami.js +1 -1
  667. package/clis/spotify/spotify.js +1 -1
  668. package/clis/stackoverflow/read.js +6 -6
  669. package/clis/stackoverflow/related.js +1 -1
  670. package/clis/stackoverflow/tag.js +1 -1
  671. package/clis/stackoverflow/user.js +1 -1
  672. package/clis/stackoverflow/utils.js +1 -1
  673. package/clis/steam/app.js +1 -1
  674. package/clis/steam/search.js +1 -1
  675. package/clis/steam/utils.js +1 -1
  676. package/clis/substack/auth.js +2 -2
  677. package/clis/substack/post-utils.js +2 -2
  678. package/clis/substack/publish.js +5 -5
  679. package/clis/suno/auth.js +2 -2
  680. package/clis/suno/download.js +5 -5
  681. package/clis/suno/generate.js +3 -3
  682. package/clis/suno/list.js +1 -1
  683. package/clis/suno/status.js +1 -1
  684. package/clis/suno/utils.js +29 -29
  685. package/clis/telegram/send.js +7 -7
  686. package/clis/telegram/shared.js +2 -2
  687. package/clis/telegram/whoami.js +1 -1
  688. package/clis/test-utils.js +1 -1
  689. package/clis/threads/post.js +23 -23
  690. package/clis/threads/shared.js +3 -3
  691. package/clis/threads/whoami.js +1 -1
  692. package/clis/tieba/hot.js +3 -3
  693. package/clis/tieba/posts.js +1 -1
  694. package/clis/tieba/read.js +2 -2
  695. package/clis/tieba/search.js +3 -3
  696. package/clis/tieba/utils.js +1 -1
  697. package/clis/tiktok/comment.js +2 -2
  698. package/clis/tiktok/creator-videos.js +3 -3
  699. package/clis/tiktok/explore.js +3 -3
  700. package/clis/tiktok/follow.js +8 -8
  701. package/clis/tiktok/following.js +4 -4
  702. package/clis/tiktok/friends.js +7 -7
  703. package/clis/tiktok/live.js +3 -3
  704. package/clis/tiktok/notifications.js +6 -6
  705. package/clis/tiktok/publish.js +16 -16
  706. package/clis/tiktok/unfollow.js +4 -4
  707. package/clis/tiktok/user.js +2 -2
  708. package/clis/tiktok/utils.js +1 -1
  709. package/clis/toutiao/article.js +1 -1
  710. package/clis/toutiao/articles.js +2 -2
  711. package/clis/toutiao/auth.js +2 -2
  712. package/clis/toutiao/hot.js +1 -1
  713. package/clis/toutiao/recommend.js +1 -1
  714. package/clis/toutiao/utils.js +2 -2
  715. package/clis/trae-solo/_actions.js +4 -4
  716. package/clis/trae-solo/_fs.js +5 -5
  717. package/clis/trae-solo/_state.js +2 -2
  718. package/clis/trae-solo/automation.js +4 -4
  719. package/clis/trae-solo/mode.js +4 -4
  720. package/clis/trae-solo/model.js +4 -4
  721. package/clis/trae-solo/renderer-storage.js +4 -4
  722. package/clis/trae-solo/settings.js +1 -1
  723. package/clis/trae-solo/skill-fs.js +1 -1
  724. package/clis/trae-solo/skill.js +12 -12
  725. package/clis/trae-solo/state-fs.js +2 -2
  726. package/clis/trae-solo/task-fs.js +5 -5
  727. package/clis/trae-solo/workspaces-fs.js +1 -1
  728. package/clis/tumblr/auth.js +2 -2
  729. package/clis/tumblr/publish.js +3 -3
  730. package/clis/tvmaze/search.js +1 -1
  731. package/clis/tvmaze/show.js +1 -1
  732. package/clis/tvmaze/utils.js +1 -1
  733. package/clis/twitter/accept.js +7 -7
  734. package/clis/twitter/article.js +7 -7
  735. package/clis/twitter/bookmark-folder.js +3 -3
  736. package/clis/twitter/bookmark-folders.js +3 -3
  737. package/clis/twitter/bookmarks.js +4 -4
  738. package/clis/twitter/delete.js +5 -5
  739. package/clis/twitter/device-follow.js +3 -3
  740. package/clis/twitter/dm-list.js +1 -1
  741. package/clis/twitter/dm-read.js +1 -1
  742. package/clis/twitter/dm-send.js +5 -5
  743. package/clis/twitter/dm-shared.js +3 -3
  744. package/clis/twitter/download.js +6 -6
  745. package/clis/twitter/followers.js +5 -5
  746. package/clis/twitter/following.js +2 -2
  747. package/clis/twitter/like.js +3 -3
  748. package/clis/twitter/likes.js +8 -8
  749. package/clis/twitter/list-add-core.js +9 -9
  750. package/clis/twitter/list-create.js +5 -5
  751. package/clis/twitter/list-remove-core.js +9 -9
  752. package/clis/twitter/list-tweets.js +7 -7
  753. package/clis/twitter/lists.js +6 -6
  754. package/clis/twitter/notifications.js +2 -2
  755. package/clis/twitter/post.js +24 -24
  756. package/clis/twitter/profile.js +7 -7
  757. package/clis/twitter/quote.js +7 -7
  758. package/clis/twitter/reply-dm.js +7 -7
  759. package/clis/twitter/reply.js +12 -12
  760. package/clis/twitter/retweet.js +3 -3
  761. package/clis/twitter/scheduled-delete.js +3 -3
  762. package/clis/twitter/scheduled-list.js +2 -2
  763. package/clis/twitter/scheduled-utils.js +3 -3
  764. package/clis/twitter/search.js +5 -5
  765. package/clis/twitter/shared.js +6 -6
  766. package/clis/twitter/thread.js +4 -4
  767. package/clis/twitter/timeline.js +3 -3
  768. package/clis/twitter/trending.js +2 -2
  769. package/clis/twitter/tweets.js +11 -11
  770. package/clis/twitter/unlike.js +3 -3
  771. package/clis/twitter/unretweet.js +3 -3
  772. package/clis/twitter/utils.js +6 -6
  773. package/clis/upwork/detail.js +2 -2
  774. package/clis/upwork/feed.js +2 -2
  775. package/clis/upwork/search.js +2 -2
  776. package/clis/upwork/utils.js +1 -1
  777. package/clis/v2ex/auth.js +2 -2
  778. package/clis/v2ex/daily.js +3 -3
  779. package/clis/v2ex/me.js +2 -2
  780. package/clis/v2ex/notifications.js +2 -2
  781. package/clis/vk/post.js +1 -1
  782. package/clis/vk/shared.js +2 -2
  783. package/clis/vk/whoami.js +1 -1
  784. package/clis/web/read.js +8 -8
  785. package/clis/wechat-channels/auth.js +2 -2
  786. package/clis/wechat-channels/publish.js +30 -30
  787. package/clis/weibo/article.js +1 -1
  788. package/clis/weibo/auth.js +3 -3
  789. package/clis/weibo/comments.js +1 -1
  790. package/clis/weibo/delete.js +2 -2
  791. package/clis/weibo/feed.js +3 -3
  792. package/clis/weibo/hot.js +1 -1
  793. package/clis/weibo/publish.js +10 -10
  794. package/clis/weibo/search.js +2 -2
  795. package/clis/weibo/user-posts.js +3 -3
  796. package/clis/weibo/user.js +2 -2
  797. package/clis/weibo/utils.js +3 -3
  798. package/clis/weixin/article.js +1 -1
  799. package/clis/weixin/create-draft.js +26 -26
  800. package/clis/weixin/download.js +2 -2
  801. package/clis/weixin/login.js +1 -1
  802. package/clis/weixin/search.js +2 -2
  803. package/clis/weixin/stats.js +3 -3
  804. package/clis/weixin/whoami.js +1 -1
  805. package/clis/weread/ai-outline.js +2 -2
  806. package/clis/weread/book-search.js +2 -2
  807. package/clis/weread/book.js +2 -2
  808. package/clis/weread/notebooks.js +1 -1
  809. package/clis/weread/search.js +1 -1
  810. package/clis/weread/shelf.js +1 -1
  811. package/clis/weread/utils.js +6 -6
  812. package/clis/weread-official/book.js +1 -1
  813. package/clis/weread-official/discover.js +1 -1
  814. package/clis/weread-official/list-apis.js +1 -1
  815. package/clis/weread-official/notes.js +1 -1
  816. package/clis/weread-official/readdata.js +1 -1
  817. package/clis/weread-official/review.js +1 -1
  818. package/clis/weread-official/search.js +1 -1
  819. package/clis/weread-official/shelf.js +1 -1
  820. package/clis/weread-official/utils.js +1 -1
  821. package/clis/wikidata/entity.js +1 -1
  822. package/clis/wikidata/search.js +1 -1
  823. package/clis/wikidata/utils.js +1 -1
  824. package/clis/wikipedia/page.js +1 -1
  825. package/clis/wikipedia/trending.js +1 -1
  826. package/clis/wikipedia/utils.js +1 -1
  827. package/clis/wordpress/login.js +1 -1
  828. package/clis/wordpress/publish.js +1 -1
  829. package/clis/wordpress/shared.js +3 -3
  830. package/clis/wordpress/whoami.js +1 -1
  831. package/clis/woshipm/article.js +1 -1
  832. package/clis/woshipm/login.js +1 -1
  833. package/clis/woshipm/stats.js +4 -4
  834. package/clis/woshipm/whoami.js +1 -1
  835. package/clis/wttr/current.js +1 -1
  836. package/clis/wttr/forecast.js +1 -1
  837. package/clis/wttr/utils.js +1 -1
  838. package/clis/xianyu/collect.js +1 -1
  839. package/clis/xianyu/inbox.js +1 -1
  840. package/clis/xianyu/item-stats.js +2 -2
  841. package/clis/xianyu/location.js +1 -1
  842. package/clis/xianyu/manage.js +1 -1
  843. package/clis/xianyu/messages.js +1 -1
  844. package/clis/xianyu/mtop.js +5 -5
  845. package/clis/xianyu/order.js +1 -1
  846. package/clis/xianyu/promote-stats.js +2 -2
  847. package/clis/xianyu/publish.js +17 -17
  848. package/clis/xianyu/rate.js +1 -1
  849. package/clis/xianyu/reply.js +1 -1
  850. package/clis/xianyu/search.js +8 -8
  851. package/clis/xianyu/seller-data.js +1 -1
  852. package/clis/xianyu/seller-list.js +1 -1
  853. package/clis/xianyu/user.js +1 -1
  854. package/clis/xiaoe/catalog.js +2 -2
  855. package/clis/xiaoe/content.js +2 -2
  856. package/clis/xiaoe/courses.js +2 -2
  857. package/clis/xiaohongshu/ask.js +6 -6
  858. package/clis/xiaohongshu/comments.js +6 -6
  859. package/clis/xiaohongshu/creator-note-detail.js +7 -7
  860. package/clis/xiaohongshu/creator-notes-summary.js +1 -1
  861. package/clis/xiaohongshu/creator-notes.js +13 -13
  862. package/clis/xiaohongshu/creator-profile.js +2 -2
  863. package/clis/xiaohongshu/creator-stats.js +2 -2
  864. package/clis/xiaohongshu/delete-note.js +7 -7
  865. package/clis/xiaohongshu/download.js +4 -4
  866. package/clis/xiaohongshu/feed.js +2 -2
  867. package/clis/xiaohongshu/follow.js +3 -3
  868. package/clis/xiaohongshu/human.js +3 -3
  869. package/clis/xiaohongshu/note-helpers.js +1 -1
  870. package/clis/xiaohongshu/note.js +2 -2
  871. package/clis/xiaohongshu/notifications.js +1 -1
  872. package/clis/xiaohongshu/publish-video.js +8 -8
  873. package/clis/xiaohongshu/publish.js +59 -59
  874. package/clis/xiaohongshu/search.js +8 -8
  875. package/clis/xiaohongshu/unfollow.js +4 -4
  876. package/clis/xiaohongshu/user-helpers.js +1 -1
  877. package/clis/xiaohongshu/user.js +2 -2
  878. package/clis/xiaoyuzhou/auth.js +3 -3
  879. package/clis/xiaoyuzhou/download.js +1 -1
  880. package/clis/xiaoyuzhou/utils.js +1 -1
  881. package/clis/xueqiu/article.js +4 -4
  882. package/clis/xueqiu/comments.js +4 -4
  883. package/clis/xueqiu/danjuan-utils.js +4 -4
  884. package/clis/xueqiu/earnings-date.js +1 -1
  885. package/clis/xueqiu/events.js +3 -3
  886. package/clis/xueqiu/hashtags.js +3 -3
  887. package/clis/xueqiu/stocks.js +3 -3
  888. package/clis/xueqiu/users.js +3 -3
  889. package/clis/xueqiu/utils.js +3 -3
  890. package/clis/yahoo-finance/quote.js +1 -1
  891. package/clis/yollomi/background.js +1 -1
  892. package/clis/yollomi/edit.js +1 -1
  893. package/clis/yollomi/face-swap.js +1 -1
  894. package/clis/yollomi/generate.js +1 -1
  895. package/clis/yollomi/object-remover.js +1 -1
  896. package/clis/yollomi/remove-bg.js +1 -1
  897. package/clis/yollomi/restore.js +1 -1
  898. package/clis/yollomi/try-on.js +1 -1
  899. package/clis/yollomi/upload.js +4 -4
  900. package/clis/yollomi/upscale.js +1 -1
  901. package/clis/yollomi/utils.js +4 -4
  902. package/clis/yollomi/video.js +1 -1
  903. package/clis/youtube/channel.js +4 -4
  904. package/clis/youtube/feed.js +2 -2
  905. package/clis/youtube/like.js +5 -5
  906. package/clis/youtube/playlist.js +7 -7
  907. package/clis/youtube/publish.js +11 -11
  908. package/clis/youtube/search.js +3 -3
  909. package/clis/youtube/subscribe.js +7 -7
  910. package/clis/youtube/subscriptions.js +1 -1
  911. package/clis/youtube/transcript-group.js +2 -2
  912. package/clis/youtube/transcript.js +13 -13
  913. package/clis/youtube/unlike.js +5 -5
  914. package/clis/youtube/unsubscribe.js +7 -7
  915. package/clis/youtube/utils.js +3 -3
  916. package/clis/youtube/video.js +4 -4
  917. package/clis/youtube/watch-later.js +2 -2
  918. package/clis/yuanbao/ask.js +18 -18
  919. package/clis/yuanbao/detail.js +1 -1
  920. package/clis/yuanbao/read.js +1 -1
  921. package/clis/yuanbao/shared.js +9 -9
  922. package/clis/yuanbao/status.js +1 -1
  923. package/clis/yuque/article.js +1 -1
  924. package/clis/yuque/whoami.js +1 -1
  925. package/clis/zhihu/answer-comments.js +2 -2
  926. package/clis/zhihu/answer-detail.js +3 -3
  927. package/clis/zhihu/answer.js +1 -1
  928. package/clis/zhihu/article-transform.js +1 -1
  929. package/clis/zhihu/article.js +1 -1
  930. package/clis/zhihu/auth.js +2 -2
  931. package/clis/zhihu/collection.js +3 -3
  932. package/clis/zhihu/collections.js +3 -3
  933. package/clis/zhihu/download.js +2 -2
  934. package/clis/zhihu/image-profile.js +6 -6
  935. package/clis/zhihu/paginate.js +3 -3
  936. package/clis/zhihu/pin.js +4 -4
  937. package/clis/zhihu/question.js +3 -3
  938. package/clis/zhihu/recommend.js +3 -3
  939. package/clis/zhihu/search.js +3 -3
  940. package/clis/zhihu/stats.js +3 -3
  941. package/clis/zhihu/user-arg.js +1 -1
  942. package/clis/zhihu/write-shared.js +7 -7
  943. package/clis/zlibrary/utils.js +6 -6
  944. package/clis/zsxq/auth.js +3 -3
  945. package/clis/zsxq/search.js +1 -1
  946. package/clis/zsxq/topic.js +1 -1
  947. package/clis/zsxq/utils.js +5 -5
  948. package/dist/src/adapter-source.js +1 -1
  949. package/dist/src/browser/analyze.js +1 -1
  950. package/dist/src/browser/article-extract.js +2 -2
  951. package/dist/src/browser/ax-snapshot.js +2 -2
  952. package/dist/src/browser/base-page.js +25 -25
  953. package/dist/src/browser/bridge.js +1 -1
  954. package/dist/src/browser/cdp.js +1 -1
  955. package/dist/src/browser/daemon-client.js +1 -1
  956. package/dist/src/browser/daemon-lifecycle.js +7 -7
  957. package/dist/src/browser/dom-helpers.js +35 -35
  958. package/dist/src/browser/dom-snapshot.js +19 -19
  959. package/dist/src/browser/errors.js +3 -3
  960. package/dist/src/browser/extract.js +5 -5
  961. package/dist/src/browser/find.js +13 -13
  962. package/dist/src/browser/fingerprint.js +2 -2
  963. package/dist/src/browser/html-tree.js +6 -6
  964. package/dist/src/browser/managed-chrome.js +1 -1
  965. package/dist/src/browser/network-cache.js +1 -1
  966. package/dist/src/browser/network-key.js +1 -1
  967. package/dist/src/browser/page.js +7 -7
  968. package/dist/src/browser/profile.js +2 -2
  969. package/dist/src/browser/proxy-test.js +8 -8
  970. package/dist/src/browser/shape-filter.js +1 -1
  971. package/dist/src/browser/shape.js +1 -1
  972. package/dist/src/browser/stealth.js +3 -3
  973. package/dist/src/browser/tabs.js +2 -2
  974. package/dist/src/browser/target-errors.js +1 -1
  975. package/dist/src/browser/target-resolver.js +23 -23
  976. package/dist/src/browser/trace.js +2 -2
  977. package/dist/src/browser/utils.js +1 -1
  978. package/dist/src/browser/verify-fixture.js +2 -2
  979. package/dist/src/browser-session-lock.js +1 -1
  980. package/dist/src/build-manifest.js +11 -11
  981. package/dist/src/capabilityRouting.js +1 -1
  982. package/dist/src/cli-argv-preprocess.js +1 -1
  983. package/dist/src/cli.js +32 -32
  984. package/dist/src/commanderAdapter.js +3 -3
  985. package/dist/src/commands/auth.js +3 -3
  986. package/dist/src/commands/daemon.js +1 -1
  987. package/dist/src/completion-fast.js +1 -1
  988. package/dist/src/completion.js +1 -1
  989. package/dist/src/constants.js +1 -1
  990. package/dist/src/convention-audit.js +2 -2
  991. package/dist/src/daemon-utils.js +1 -1
  992. package/dist/src/daemon.js +1 -1
  993. package/dist/src/discovery.js +2 -2
  994. package/dist/src/doctor.js +9 -9
  995. package/dist/src/download/article-download.js +15 -15
  996. package/dist/src/download/index.js +4 -4
  997. package/dist/src/download/media-download.js +1 -1
  998. package/dist/src/download/progress.js +3 -3
  999. package/dist/src/electron-apps.js +1 -1
  1000. package/dist/src/errors.js +2 -2
  1001. package/dist/src/execution.js +2 -2
  1002. package/dist/src/external.js +1 -1
  1003. package/dist/src/help.js +8 -8
  1004. package/dist/src/hooks.js +1 -1
  1005. package/dist/src/interceptor.js +21 -21
  1006. package/dist/src/launcher.js +7 -7
  1007. package/dist/src/logger.js +8 -8
  1008. package/dist/src/main.js +7 -7
  1009. package/dist/src/observation/artifact.js +5 -5
  1010. package/dist/src/observation/retention.js +1 -1
  1011. package/dist/src/output.js +2 -2
  1012. package/dist/src/package-paths.js +1 -1
  1013. package/dist/src/pipeline/executor.js +1 -1
  1014. package/dist/src/pipeline/registry.js +1 -1
  1015. package/dist/src/pipeline/steps/browser.js +1 -1
  1016. package/dist/src/pipeline/steps/download.js +1 -1
  1017. package/dist/src/pipeline/steps/fetch.js +6 -6
  1018. package/dist/src/pipeline/steps/intercept.js +1 -1
  1019. package/dist/src/pipeline/steps/tap.js +17 -17
  1020. package/dist/src/pipeline/steps/transform.js +1 -1
  1021. package/dist/src/pipeline/template.js +1 -1
  1022. package/dist/src/plugin-manifest.js +1 -1
  1023. package/dist/src/plugin-scaffold.js +19 -19
  1024. package/dist/src/plugin.js +12 -12
  1025. package/dist/src/rate-limit.js +1 -1
  1026. package/dist/src/registry.js +1 -1
  1027. package/dist/src/runtime-detect.js +1 -1
  1028. package/dist/src/runtime.js +1 -1
  1029. package/dist/src/scripts/framework.js +1 -1
  1030. package/dist/src/scripts/interact.js +1 -1
  1031. package/dist/src/scripts/store.js +1 -1
  1032. package/dist/src/serialization.js +2 -2
  1033. package/dist/src/session-lease.js +1 -1
  1034. package/dist/src/snapshotFormatter.js +2 -2
  1035. package/dist/src/tui.js +12 -12
  1036. package/dist/src/user-runtime.js +1 -1
  1037. package/dist/src/utils.d.ts +12 -0
  1038. package/dist/src/utils.js +4 -4
  1039. package/dist/src/validate.js +2 -2
  1040. package/dist/src/verify.js +2 -2
  1041. package/dist/src/version.js +1 -1
  1042. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import{cli as E,Strategy as q}from"@jackwener/opencli/registry";import{ArgumentError as l,AuthRequiredError as b,CommandExecutionError as u}from"@jackwener/opencli/errors";const w="www.linkedin.com",J="https://www.linkedin.com/sales/",B="(entityUrn,objectUrn,firstName,lastName,fullName,headline,degree,inmailRestriction,memberBadges,defaultPosition)",k="https://www.linkedin.com/sales-api/salesApiCredits?q=findCreditGrant&creditGrantType=LSS_INMAIL",D="https://www.linkedin.com/sales-api/salesApiMessageActions?action=createMessage";function c(e){return String(e??"").replace(/[\u00a0\u202f]/g," ").replace(/\s+/g," ").trim()}function R(e,t,n=t){const r=c(e[t]);if(!r)throw new l(`${n} is required`);return r}function f(e){if(e&&typeof e==="object"&&"data"in e&&"session"in e)return e.data;return e}function F(e){const t=String(e||"").toLowerCase();return t==="linkedin.com"||t.endsWith(".linkedin.com")}function g(e){const t=c(e),n=t.match(/^urn:li:fs_salesProfile:\(([^,()]+),([^,()]+),([^,()]+)\)$/);if(!n)return null;if(!m(n[1],n[2],n[3]))return null;return{profileId:n[1],authType:n[2],authToken:n[3],entityUrn:t}}function m(e,t,n){return[e,t,n].every((r)=>{const i=c(r).toLowerCase();return i&&i!=="undefined"&&i!=="null"&&i!=="not_available"})}function N({profileId:e,authType:t,authToken:n}){return`https://www.linkedin.com/sales/lead/${encodeURIComponent(e)},${encodeURIComponent(t)},${encodeURIComponent(n)}`}function v(e){const t=c(e),n=g(t);if(n)return n;try{const r=new URL(t);if(r.protocol!=="https:"||r.username||r.password||r.port||!F(r.hostname))return null;const i=r.pathname.match(/^\/sales\/lead\/([^,/]+),([^,/]+),([^/]+)\/?$/i);if(i){const a=decodeURIComponent(i[1]),s=decodeURIComponent(i[2]),d=decodeURIComponent(i[3]);if(!m(a,s,d))return null;return{profileId:a,authType:s,authToken:d,entityUrn:`urn:li:fs_salesProfile:(${a},${s},${d})`}}const o=r.pathname.match(/^\/in\/([^/]+)\/?$/i);if(o)return{profileId:decodeURIComponent(o[1]),authType:"",authToken:"",entityUrn:""}}catch{return null}return null}function G(e){return encodeURIComponent(e).replace(/\(/g,"%28").replace(/\)/g,"%29")}function U(e){if(!e?.profileId||!e?.authType||!e?.authToken)return"";return`https://www.linkedin.com/sales-api/salesApiProfiles/${`(profileId:${e.profileId},authType:${e.authType},authToken:${e.authToken})`}?decoration=${G(B)}`}function H(){const e=new Uint8Array(8);if(globalThis.crypto?.getRandomValues)globalThis.crypto.getRandomValues(e);else for(let t=0;t<e.length;t+=1)e[t]=Math.floor(Math.random()*256);return Array.from(e,(t)=>t.toString(16).padStart(2,"0")).join("")}function T({recipientUrn:e,subject:t,body:n,trackingId:r=H(),copyToCrm:i=!1}){const o=c(e);if(!g(o))throw new l("--recipient must resolve to a Sales Navigator lead urn");const a=c(t),s=String(n??"").trim();if(!a)throw new l("--subject is required");if(!s)throw new l("--body is required");if(a.length>200)throw new l("--subject must be 200 characters or fewer");if(s.length>1900)throw new l("--body must be 1900 characters or fewer");return{createMessageRequest:{recipients:[o],subject:a,body:s,copyToCrm:Boolean(i),trackingId:r}}}function _(e){const n=(Array.isArray(e?.elements)?e.elements:[]).find((o)=>o?.type==="LSS_INMAIL"&&Number.isInteger(o.value));if(n)return n.value;const r=[],i=(o)=>{if(o===null||o===void 0)return;if(typeof o==="number"&&Number.isFinite(o))r.push(o);if(Array.isArray(o))o.forEach(i);else if(typeof o==="object"){for(const[a,s]of Object.entries(o))if(/remaining|available|balance|value/i.test(a)&&typeof s==="number")r.unshift(s);else if(!/^count$|^start$|^id$/i.test(a))i(s)}};i(e);return r.find((o)=>Number.isInteger(o)&&o>=0)??null}function p(e,t,n={}){return String.raw`(async () => {
1
+ import{cli as q,Strategy as J}from"@jackwener/opencli/registry";import{ArgumentError as l,AuthRequiredError as b,CommandExecutionError as u}from"@jackwener/opencli/errors";const w="www.linkedin.com",B="https://www.linkedin.com/sales/",D="(entityUrn,objectUrn,firstName,lastName,fullName,headline,degree,inmailRestriction,memberBadges,defaultPosition)",k="https://www.linkedin.com/sales-api/salesApiCredits?q=findCreditGrant&creditGrantType=LSS_INMAIL",F="https://www.linkedin.com/sales-api/salesApiMessageActions?action=createMessage";function c(e){return String(e??"").replace(/[\u00a0\u202f]/g," ").replace(/\s+/g," ").trim()}function R(e,t,n=t){const r=c(e[t]);if(!r)throw new l(`${n} is required`);return r}function f(e){if(e&&typeof e==="object"&&"data"in e&&"session"in e)return e.data;return e}function G(e){const t=String(e||"").toLowerCase();return t==="linkedin.com"||t.endsWith(".linkedin.com")}function g(e){const t=c(e),n=t.match(/^urn:li:fs_salesProfile:\(([^,()]+),([^,()]+),([^,()]+)\)$/);if(!n)return null;if(!m(n[1],n[2],n[3]))return null;return{profileId:n[1],authType:n[2],authToken:n[3],entityUrn:t}}function m(e,t,n){return[e,t,n].every((r)=>{const i=c(r).toLowerCase();return i&&i!=="undefined"&&i!=="null"&&i!=="not_available"})}function N({profileId:e,authType:t,authToken:n}){return`https://www.linkedin.com/sales/lead/${encodeURIComponent(e)},${encodeURIComponent(t)},${encodeURIComponent(n)}`}function v(e){const t=c(e),n=g(t);if(n)return n;try{const r=new URL(t);if(r.protocol!=="https:"||r.username||r.password||r.port||!G(r.hostname))return null;const i=r.pathname.match(/^\/sales\/lead\/([^,/]+),([^,/]+),([^/]+)\/?$/i);if(i){const a=decodeURIComponent(i[1]),s=decodeURIComponent(i[2]),d=decodeURIComponent(i[3]);if(!m(a,s,d))return null;return{profileId:a,authType:s,authToken:d,entityUrn:`urn:li:fs_salesProfile:(${a},${s},${d})`}}const o=r.pathname.match(/^\/in\/([^/]+)\/?$/i);if(o)return{profileId:decodeURIComponent(o[1]),authType:"",authToken:"",entityUrn:""}}catch{return null}return null}function H(e){return encodeURIComponent(e).replace(/\(/g,"%28").replace(/\)/g,"%29")}function U(e){if(!e?.profileId||!e?.authType||!e?.authToken)return"";return`https://www.linkedin.com/sales-api/salesApiProfiles/${`(profileId:${e.profileId},authType:${e.authType},authToken:${e.authToken})`}?decoration=${H(D)}`}function z(){const e=new Uint8Array(8);if(globalThis.crypto?.getRandomValues)globalThis.crypto.getRandomValues(e);else for(let t=0;t<e.length;t+=1)e[t]=Math.floor(Math.random()*256);return Array.from(e,(t)=>t.toString(16).padStart(2,"0")).join("")}function T({recipientUrn:e,subject:t,body:n,trackingId:r=z(),copyToCrm:i=!1}){const o=c(e);if(!g(o))throw new l("--recipient must resolve to a Sales Navigator lead urn");const a=c(t),s=String(n??"").trim();if(!a)throw new l("--subject is required");if(!s)throw new l("--body is required");if(a.length>200)throw new l("--subject must be 200 characters or fewer");if(s.length>1900)throw new l("--body must be 1900 characters or fewer");return{createMessageRequest:{recipients:[o],subject:a,body:s,copyToCrm:Boolean(i),trackingId:r}}}function _(e){const n=(Array.isArray(e?.elements)?e.elements:[]).find((o)=>o?.type==="LSS_INMAIL"&&Number.isInteger(o.value));if(n)return n.value;const r=[],i=(o)=>{if(o===null||o===void 0)return;if(typeof o==="number"&&Number.isFinite(o))r.push(o);if(Array.isArray(o))o.forEach(i);else if(typeof o==="object"){for(const[a,s]of Object.entries(o))if(/remaining|available|balance|value/i.test(a)&&typeof s==="number")r.unshift(s);else if(!/^count$|^start$|^id$/i.test(a))i(s)}};i(e);return r.find((o)=>Number.isInteger(o)&&o>=0)??null}function p(e,t,n={}){return String.raw`(async () => {
2
2
  const headers = {
3
3
  'csrf-token': ${JSON.stringify(t)},
4
4
  'x-restli-protocol-version': '2.0.0',
@@ -21,7 +21,7 @@ import{cli as E,Strategy as q}from"@jackwener/opencli/registry";import{ArgumentE
21
21
  } catch (e) {
22
22
  return ['error', 0, null, '', 'fetch failed: ' + ((e && e.message) || String(e))];
23
23
  }
24
- })()`}function h(e,t,{requireJson:n=!0}={}){if(Array.isArray(e)){const[r,i,o,a,s]=e;e={authRequired:r==="auth",error:r==="error"?s||`HTTP ${i}`:"",status:i,json:o,text:a}}if(e?.authRequired)throw new b(w,`${t} auth failed.`);if(e?.error)throw new u(`${t} failed`,e.error);if(!e||typeof e!=="object"||Array.isArray(e))throw new u(`${t} returned malformed response`);if(n&&(!e.json||typeof e.json!=="object"||Array.isArray(e.json)))throw new u(`${t} returned malformed response`,"missing_json");return e}function A(e,t){const n=c(e),r=c(t).split(" ")[0];return n.includes("You sent a Sales Navigator message")&&(!r||n.includes(r))}async function z(e){const n=(await e.getCookies({url:"https://www.linkedin.com"})).find((r)=>r.name==="JSESSIONID")?.value;if(!n)throw new b(w,"LinkedIn JSESSIONID cookie not found. Please sign in to LinkedIn.");return n.replace(/^\"|\"$/g,"")}async function V(e,t,n){if(!t)throw new l("--recipient must be a Sales Navigator lead URL, Sales Navigator profile URL, LinkedIn /in/ URL, or urn:li:fs_salesProfile:(...)");if(t.entityUrn&&t.authType&&t.authToken)return t;await e.goto(`https://www.linkedin.com/sales/lead/${encodeURIComponent(t.profileId)}`);await e.wait(6);const r=f(await e.evaluate(String.raw`(() => {
24
+ })()`}function h(e,t,{requireJson:n=!0}={}){if(Array.isArray(e)){const[r,i,o,a,s]=e;e={authRequired:r==="auth",error:r==="error"?s||`HTTP ${i}`:"",status:i,json:o,text:a}}if(e?.authRequired)throw new b(w,`${t} auth failed.`);if(e?.error)throw new u(`${t} failed`,e.error);if(!e||typeof e!=="object"||Array.isArray(e))throw new u(`${t} returned malformed response`);if(n&&(!e.json||typeof e.json!=="object"||Array.isArray(e.json)))throw new u(`${t} returned malformed response`,"missing_json");return e}function A(e,t){const n=c(e),r=c(t).split(" ")[0];return n.includes("You sent a Sales Navigator message")&&(!r||n.includes(r))}async function V(e){const n=(await e.getCookies({url:"https://www.linkedin.com"})).find((r)=>r.name==="JSESSIONID")?.value;if(!n)throw new b(w,"LinkedIn JSESSIONID cookie not found. Please sign in to LinkedIn.");return n.replace(/^\"|\"$/g,"")}async function W(e,t,n){if(!t)throw new l("--recipient must be a Sales Navigator lead URL, Sales Navigator profile URL, LinkedIn /in/ URL, or urn:li:fs_salesProfile:(...)");if(t.entityUrn&&t.authType&&t.authToken)return t;await e.goto(`https://www.linkedin.com/sales/lead/${encodeURIComponent(t.profileId)}`);await e.wait(6);const r=f(await e.evaluate(String.raw`(() => {
25
25
  const href = location.href;
26
26
  const text = document.body ? document.body.innerText : '';
27
27
  const resourceUrns = Array.from(performance.getEntriesByType('resource'))
@@ -30,4 +30,4 @@ import{cli as E,Strategy as q}from"@jackwener/opencli/registry";import{ArgumentE
30
30
  .slice(-20);
31
31
  return { href, text: text.slice(0, 1000), resourceUrns };
32
32
  })()`)),i=String(r?.href||"").match(/\/sales\/lead\/([^,/]+),([^,/]+),([^/?#]+)/i);if(i&&m(i[1],i[2],i[3]))return{profileId:decodeURIComponent(i[1]),authType:decodeURIComponent(i[2]),authToken:decodeURIComponent(i[3]),entityUrn:`urn:li:fs_salesProfile:(${decodeURIComponent(i[1])},${decodeURIComponent(i[2])},${decodeURIComponent(i[3])})`};for(const o of r?.resourceUrns||[]){const a=String(o).match(/profileId:([^,)]+),authType:([^,)]+),authToken:([^,)]+)\)/);if(a&&a[1]===t.profileId)return{profileId:a[1],authType:a[2],authToken:a[3],entityUrn:`urn:li:fs_salesProfile:(${a[1]},${a[2]},${a[3]})`}}throw new u("Could not resolve Sales Navigator auth token for recipient",`Observed URL: ${r?.href||"url_not_available"}
33
- Body: ${c(r?.text||"").slice(0,500)}`)}function $(e){const t=e?.data||e||{},n=t.defaultPosition||(Array.isArray(t.positions)?t.positions.find((r)=>r.current)||t.positions[0]:{})||{};return{recipient:c(t.fullName||[t.firstName,t.lastName].filter(Boolean).join(" ")),title:c(n.title||t.headline||""),company:c(n.companyName||n.company?.name||""),degree:c(t.degree||""),inmail_restriction:c(t.inmailRestriction||""),open_link:Boolean(t.memberBadges?.openLink)}}function j(e){const t=$(e);if(!t.recipient)throw new u("Sales Navigator profile lookup returned malformed profile data","missing_recipient_name");return t}E({site:"linkedin",name:"salesnav-message",access:"write",description:"Send or dry-run a LinkedIn Sales Navigator InMail to a lead using the Sales Navigator messaging API",domain:w,strategy:q.UI,browser:!0,args:[{name:"recipient",type:"string",required:!0,positional:!0,help:"Sales Navigator lead URL, LinkedIn /in/ URL from salesnav-search, or urn:li:fs_salesProfile:(...)"},{name:"subject",type:"string",required:!0,help:"InMail subject"},{name:"body",fromFile:!0,type:"string",required:!0,help:"InMail body"},{name:"send",type:"bool",default:!1,help:"Actually send the InMail. Default is dry-run validation only."},{name:"copy-to-crm",type:"bool",default:!1,help:"Set Sales Navigator copyToCrm on the message request"}],columns:["status","recipient","title","company","credits_remaining","credits_before","credits_after","sent_in_salesnav","message_chars","subject_chars","recipient_urn","degree","inmail_restriction","open_link"],func:async(e,t)=>{if(!e)throw new u("Browser session required for linkedin salesnav-message");const n=R(t,"recipient","--recipient"),r=R(t,"subject","--subject"),i=String(t.body??"").trim();if(!i)throw new l("--body is required");await e.goto(J);await e.wait(4);const o=await z(e),a=await V(e,v(n),o);let s={recipient:"",title:"",company:"",degree:"",inmail_restriction:"",open_link:!1};const d=U(a);if(d){const O=h(f(await e.evaluate(p(d,o))),"LinkedIn Sales Navigator profile API");s=j(O.json)}if(s.inmail_restriction&&s.inmail_restriction!=="NO_RESTRICTION")throw new u("Sales Navigator InMail blocked by recipient restriction",s.inmail_restriction);const C=h(f(await e.evaluate(p(k,o))),"LinkedIn Sales Navigator credits API"),y=_(C?.json),L=T({recipientUrn:a.entityUrn,subject:r,body:i,copyToCrm:t["copy-to-crm"]});if(!t.send)return[{status:"validated_dry_run",recipient:s.recipient,title:s.title,company:s.company,credits_remaining:y,credits_before:y,credits_after:"",sent_in_salesnav:!1,message_chars:i.length,subject_chars:r.length,recipient_urn:a.entityUrn,degree:s.degree,inmail_restriction:s.inmail_restriction,open_link:s.open_link}];const P=h(f(await e.evaluate(p(D,o,{method:"POST",accept:"application/vnd.linkedin.normalized+json+2.1",body:L}))),"LinkedIn Sales Navigator message API",{requireJson:!1});await e.wait(3);const M=h(f(await e.evaluate(p(k,o))),"LinkedIn Sales Navigator credits API after send"),I=_(M?.json);await e.goto(N(a));await e.wait(6);const x=f(await e.evaluate('document.body ? document.body.innerText : ""')),S=A(x,s.recipient);if(!S)throw new u("Sales Navigator post-send verification failed","Sent activity was not found on the Sales Navigator lead page.");return[{status:"sent",recipient:s.recipient,title:s.title,company:s.company,credits_remaining:I,credits_before:y,credits_after:I,sent_in_salesnav:S,message_chars:i.length,subject_chars:r.length,recipient_urn:a.entityUrn,degree:s.degree,inmail_restriction:s.inmail_restriction,open_link:s.open_link}]}});export const __test__={normalizeWhitespace:c,parseSalesProfileUrn:g,isResolvedSalesProfileParts:m,parseRecipient:v,salesLeadUrlFromParts:N,profileApiUrl:U,buildCreateMessagePayload:T,extractRemainingCredits:_,profileSummary:$,requireProfileSummary:j,salesPageShowsSentMessage:A};
33
+ Body: ${c(r?.text||"").slice(0,500)}`)}function j(e){const t=e?.data||e||{},n=t.defaultPosition||(Array.isArray(t.positions)?t.positions.find((r)=>r.current)||t.positions[0]:{})||{};return{recipient:c(t.fullName||[t.firstName,t.lastName].filter(Boolean).join(" ")),title:c(n.title||t.headline||""),company:c(n.companyName||n.company?.name||""),degree:c(t.degree||""),inmail_restriction:c(t.inmailRestriction||""),open_link:Boolean(t.memberBadges?.openLink)}}function C(e){const t=j(e);if(!t.recipient)throw new u("Sales Navigator profile lookup returned malformed profile data","missing_recipient_name");return t}q({site:"linkedin",name:"salesnav-message",access:"write",description:"Send or dry-run a LinkedIn Sales Navigator InMail to a lead using the Sales Navigator messaging API",domain:w,strategy:J.UI,browser:!0,args:[{name:"recipient",type:"string",required:!0,positional:!0,help:"Sales Navigator lead URL, LinkedIn /in/ URL from salesnav-search, or urn:li:fs_salesProfile:(...)"},{name:"subject",type:"string",required:!0,help:"InMail subject"},{name:"body",fromFile:!0,type:"string",required:!0,help:"InMail body"},{name:"send",type:"bool",default:!1,help:"Actually send the InMail. Default is dry-run validation only."},{name:"copy-to-crm",type:"bool",default:!1,help:"Set Sales Navigator copyToCrm on the message request"}],columns:["status","recipient","title","company","credits_remaining","credits_before","credits_after","sent_in_salesnav","message_chars","subject_chars","recipient_urn","degree","inmail_restriction","open_link"],func:async(e,t)=>{if(!e)throw new u("Browser session required for linkedin salesnav-message");const n=R(t,"recipient","--recipient"),r=R(t,"subject","--subject"),i=String(t.body??"").trim();if(!i)throw new l("--body is required");await e.goto(B);await e.wait(4);const o=await V(e),a=await W(e,v(n),o);let s={recipient:"",title:"",company:"",degree:"",inmail_restriction:"",open_link:!1};const d=U(a);if(d){const E=h(f(await e.evaluate(p(d,o))),"LinkedIn Sales Navigator profile API");s=C(E.json)}if(s.inmail_restriction&&s.inmail_restriction!=="NO_RESTRICTION")throw new u("Sales Navigator InMail blocked by recipient restriction",s.inmail_restriction);const L=h(f(await e.evaluate(p(k,o))),"LinkedIn Sales Navigator credits API"),y=_(L?.json),P=T({recipientUrn:a.entityUrn,subject:r,body:i,copyToCrm:t["copy-to-crm"]});if(!t.send)return[{status:"validated_dry_run",recipient:s.recipient,title:s.title,company:s.company,credits_remaining:y,credits_before:y,credits_after:"",sent_in_salesnav:!1,message_chars:i.length,subject_chars:r.length,recipient_urn:a.entityUrn,degree:s.degree,inmail_restriction:s.inmail_restriction,open_link:s.open_link}];const M=h(f(await e.evaluate(p(F,o,{method:"POST",accept:"application/vnd.linkedin.normalized+json+2.1",body:P}))),"LinkedIn Sales Navigator message API",{requireJson:!1});await e.wait(3);const x=h(f(await e.evaluate(p(k,o))),"LinkedIn Sales Navigator credits API after send"),I=_(x?.json);await e.goto(N(a));await e.wait(6);const O=f(await e.evaluate('document.body ? document.body.innerText : ""')),S=A(O,s.recipient);if(!S)throw new u("Sales Navigator post-send verification failed","Sent activity was not found on the Sales Navigator lead page.");return[{status:"sent",recipient:s.recipient,title:s.title,company:s.company,credits_remaining:I,credits_before:y,credits_after:I,sent_in_salesnav:S,message_chars:i.length,subject_chars:r.length,recipient_urn:a.entityUrn,degree:s.degree,inmail_restriction:s.inmail_restriction,open_link:s.open_link}]}});export const __test__={normalizeWhitespace:c,parseSalesProfileUrn:g,isResolvedSalesProfileParts:m,parseRecipient:v,salesLeadUrlFromParts:N,profileApiUrl:U,buildCreateMessagePayload:T,extractRemainingCredits:_,profileSummary:j,requireProfileSummary:C,salesPageShowsSentMessage:A};
@@ -1,15 +1,15 @@
1
- import{cli as _,Strategy as k}from"@jackwener/opencli/registry";import{ArgumentError as O,AuthRequiredError as f,CommandExecutionError as T,EmptyResultError as I}from"@jackwener/opencli/errors";const H="www.linkedin.com",j="https://www.linkedin.com/sales/",v="https://www.linkedin.com/sales-api/salesApiLeadSearch",S="com.linkedin.sales.deco.desktop.searchv2.LeadSearchResult-14",z=25;function Y(J){return String(J??"").replace(/[  ]/g," ").replace(/\s+/g," ").trim()}function L(J,Q,V=Q){const $=Y(J[Q]);if(!$)throw new O(`${V} is required`);return $}function W(J){if(J===void 0||J===null||J==="")return 25;const Q=Number(J);if(!Number.isInteger(Q)||Q<1||Q>500)throw new O("--limit must be an integer between 1 and 500");return Q}function A(J){if(J&&typeof J==="object"&&"data"in J&&"session"in J)return J.data;return J}function x(J,Q){const V="(spellCorrectionEnabled:true,recentSearchParam:(doLogHistory:true),keywords:"+encodeURIComponent(J)+")";return v+"?q=searchQuery&query="+V+"&start="+Q+"&count="+z+"&decorationId="+S}function U(J,Q){return String.raw`(async () => {
1
+ import{cli as P,Strategy as v}from"@jackwener/opencli/registry";import{ArgumentError as S,AuthRequiredError as y,CommandExecutionError as i,EmptyResultError as R}from"@jackwener/opencli/errors";const f="www.linkedin.com",q="https://www.linkedin.com/sales/",b="https://www.linkedin.com/sales-api/salesApiLeadSearch",C="com.linkedin.sales.deco.desktop.searchv2.LeadSearchResult-14",k=25;function o(e){return String(e??"").replace(/[  ]/g," ").replace(/\s+/g," ").trim()}function U(e,r,t=r){const s=o(e[r]);if(!s)throw new S(`${t} is required`);return s}function I(e){if(e===void 0||e===null||e==="")return 25;const r=Number(e);if(!Number.isInteger(r)||r<1||r>500)throw new S("--limit must be an integer between 1 and 500");return r}function j(e){if(e&&typeof e==="object"&&"data"in e&&"session"in e)return e.data;return e}function N(e,r){const t="(spellCorrectionEnabled:true,recentSearchParam:(doLogHistory:true),keywords:"+encodeURIComponent(e)+")";return b+"?q=searchQuery&query="+t+"&start="+r+"&count="+k+"&decorationId="+C}function O(e,r){return String.raw`(async () => {
2
2
  const headers = {
3
- 'csrf-token': ${JSON.stringify(Q)},
3
+ 'csrf-token': ${JSON.stringify(r)},
4
4
  'x-restli-protocol-version': '2.0.0',
5
5
  accept: 'application/json',
6
6
  };
7
7
  try {
8
- const res = await fetch(${JSON.stringify(J)}, { credentials: 'include', headers });
8
+ const res = await fetch(${JSON.stringify(e)}, { credentials: 'include', headers });
9
9
  if (res.status === 401 || res.status === 403) return { authRequired: true, status: res.status };
10
10
  if (!res.ok) return { error: 'HTTP ' + res.status };
11
11
  return { json: await res.json() };
12
12
  } catch (e) {
13
13
  return { error: 'fetch failed: ' + ((e && e.message) || String(e)) };
14
14
  }
15
- })()`}function K(J){const Q=String(J||"").match(/fs_salesProfile:\(([^,)]+)/);return Q&&Q[1]?"https://www.linkedin.com/in/"+Q[1]:""}function D(J){const Q=String(J||"").match(/^urn:li:fs_salesProfile:\(([^,()]+),([^,()]+),([^,()]+)\)$/);if(!Q)return"";return`https://www.linkedin.com/sales/lead/${encodeURIComponent(Q[1])},${encodeURIComponent(Q[2])},${encodeURIComponent(Q[3])}`}function C(J){if(!J||typeof J!=="object"||!Array.isArray(J.elements))throw new T("Sales Navigator lead search API returned malformed payload");const Q=[];for(const V of J.elements){if(!V||typeof V!=="object")throw new T("Sales Navigator lead search API returned malformed lead row");const $=Array.isArray(V.currentPositions)?V.currentPositions:[],M=Array.isArray(V.pastPositions)?V.pastPositions:[],b=$[0]||M[0]||{},G=Y(V.fullName||[V.firstName,V.lastName].filter(Boolean).join(" "));if(!G)throw new T("Sales Navigator lead row missing name");const X=Y(V.entityUrn||"");if(!K(X))throw new T("Sales Navigator lead row missing profile identity");Q.push({name:G,title:Y(b.title||""),company:Y(b.companyName||""),location:Y(V.geoRegion||""),degree:Y(V.degree||""),profile_url:K(X),lead_url:D(X),recipient_urn:X})}return Q}function N(J){if(J?.authRequired)throw new f(H,"LinkedIn Sales Navigator API auth failed (HTTP "+(J.status||"")+"). Confirm the account has Sales Navigator access.");if(J?.error)throw new T("Sales Navigator lead search API returned an unexpected response",J.error);if(!J||!J.json)throw new T("Sales Navigator lead search API returned an unexpected response","no_json");return J.json}_({site:"linkedin",name:"salesnav-search",access:"read",description:"Search LinkedIn Sales Navigator for people leads by keyword",domain:H,strategy:k.UI,browser:!0,args:[{name:"keywords",type:"string",required:!0,positional:!0,help:'People search keywords, e.g. "quality manager food manufacturing"'},{name:"limit",type:"number",default:25,help:"Maximum leads to return (1-500, fetched 25 per request)"}],columns:["rank","name","title","company","location","degree","profile_url","lead_url","recipient_urn"],func:async(J,Q)=>{if(!J)throw new T("Browser session required for linkedin salesnav-search");const V=L(Q,"keywords","--keywords"),$=W(Q.limit);await J.goto(j);await J.wait(6);const b=(await J.getCookies({url:"https://www.linkedin.com"})).find((B)=>B.name==="JSESSIONID")?.value;if(!b)throw new f(H,"LinkedIn JSESSIONID cookie not found. Please sign in to LinkedIn.");const G=b.replace(/^\"|\"$/g,""),X=[],F=new Set;for(let B=0;X.length<$&&B<2000;B+=z){const P=A(await J.evaluate(U(x(V,B),G))),R=N(P),q=C(R);if(q.length===0)break;for(const Z of q){const w=Z.profile_url||Z.name.toLowerCase();if(F.has(w))continue;F.add(w);X.push(Z)}await J.wait(1)}if(X.length===0)throw new I("linkedin salesnav-search","No Sales Navigator leads were found.");return X.slice(0,$).map((B,P)=>({rank:P+1,...B}))}});export const __test__={normalizeWhitespace:Y,parseLimit:W,leadSearchUrl:x,profileUrlFromEntityUrn:K,leadUrlFromEntityUrn:D,parseLeads:C,requireLeadSearchResult:N};
15
+ })()`}function m(e){const r=String(e||"").match(/fs_salesProfile:\(([^,)]+)/);return r&&r[1]?"https://www.linkedin.com/in/"+r[1]:""}function A(e){const r=String(e||"").match(/^urn:li:fs_salesProfile:\(([^,()]+),([^,()]+),([^,()]+)\)$/);if(!r)return"";return`https://www.linkedin.com/sales/lead/${encodeURIComponent(r[1])},${encodeURIComponent(r[2])},${encodeURIComponent(r[3])}`}function E(e){if(!e||typeof e!=="object"||!Array.isArray(e.elements))throw new i("Sales Navigator lead search API returned malformed payload");const r=[];for(const t of e.elements){if(!t||typeof t!=="object")throw new i("Sales Navigator lead search API returned malformed lead row");const s=Array.isArray(t.currentPositions)?t.currentPositions:[],w=Array.isArray(t.pastPositions)?t.pastPositions:[],c=s[0]||w[0]||{},l=o(t.fullName||[t.firstName,t.lastName].filter(Boolean).join(" "));if(!l)throw new i("Sales Navigator lead row missing name");const n=o(t.entityUrn||"");if(!m(n))throw new i("Sales Navigator lead row missing profile identity");r.push({name:l,title:o(c.title||""),company:o(c.companyName||""),location:o(t.geoRegion||""),degree:o(t.degree||""),profile_url:m(n),lead_url:A(n),recipient_urn:n})}return r}function _(e){if(e?.authRequired)throw new y(f,"LinkedIn Sales Navigator API auth failed (HTTP "+(e.status||"")+"). Confirm the account has Sales Navigator access.");if(e?.error)throw new i("Sales Navigator lead search API returned an unexpected response",e.error);if(!e||!e.json)throw new i("Sales Navigator lead search API returned an unexpected response","no_json");return e.json}P({site:"linkedin",name:"salesnav-search",access:"read",description:"Search LinkedIn Sales Navigator for people leads by keyword",domain:f,strategy:v.UI,browser:!0,args:[{name:"keywords",type:"string",required:!0,positional:!0,help:'People search keywords, e.g. "quality manager food manufacturing"'},{name:"limit",type:"number",default:25,help:"Maximum leads to return (1-500, fetched 25 per request)"}],columns:["rank","name","title","company","location","degree","profile_url","lead_url","recipient_urn"],func:async(e,r)=>{if(!e)throw new i("Browser session required for linkedin salesnav-search");const t=U(r,"keywords","--keywords"),s=I(r.limit);await e.goto(q);await e.wait(6);const c=(await e.getCookies({url:"https://www.linkedin.com"})).find((a)=>a.name==="JSESSIONID")?.value;if(!c)throw new y(f,"LinkedIn JSESSIONID cookie not found. Please sign in to LinkedIn.");const l=c.replace(/^\"|\"$/g,""),n=[],h=new Set;for(let a=0;n.length<s&&a<2000;a+=k){const u=j(await e.evaluate(O(N(t,a),l))),L=_(u),p=E(L);if(p.length===0)break;for(const d of p){const g=d.profile_url||d.name.toLowerCase();if(h.has(g))continue;h.add(g);n.push(d)}await e.wait(1)}if(n.length===0)throw new R("linkedin salesnav-search","No Sales Navigator leads were found.");return n.slice(0,s).map((a,u)=>({rank:u+1,...a}))}});export const __test__={normalizeWhitespace:o,parseLimit:I,leadSearchUrl:N,profileUrlFromEntityUrn:m,leadUrlFromEntityUrn:A,parseLeads:E,requireLeadSearchResult:_};
@@ -1 +1 @@
1
- import{cli as R,Strategy as M}from"@jackwener/opencli/registry";import{ArgumentError as H,CommandExecutionError as O,EmptyResultError as y}from"@jackwener/opencli/errors";import{THREAD_DECORATION as W,THREADS_BASE as f,encodeRestliDecoration as S,fetchInboxRows as v,fetchSalesnavJson as T,getCsrf as x,normalizeWhitespace as X,parseLimit as b}from"./salesnav-inbox.js";const A="www.linkedin.com",w="https://www.linkedin.com/sales/inbox/",k=200,P=20;function I(Q){const Y=String(Q||"").toLowerCase();return Y==="linkedin.com"||Y.endsWith(".linkedin.com")}function C(Q){const Y=X(Q),J=Y.match(/^urn:li:fs_salesProfile:\(([^,()]+),([^,()]+),([^,()]+)\)$/);if(!J)return"";if([J[1],J[2],J[3]].map(($)=>X($).toLowerCase()).some(($)=>!$||$==="undefined"||$==="null"||$==="not_available"))return"";return Y}function q(Q){const Y=X(Q);if(!Y)return["empty",""];if(/^2-[A-Za-z0-9+/=_-]+$/.test(Y))return["thread_id",Y];if(/^urn:li:fs_salesProfile:\(/.test(Y)){const J=C(Y);if(!J)throw new H("Sales Navigator recipient urn must be urn:li:fs_salesProfile:(profileId,authType,authToken)");return["recipient_urn",J]}try{const J=new URL(Y);if(J.protocol!=="https:"||J.username||J.password||J.port||!I(J.hostname))return["name",Y.toLowerCase()];const K=J.pathname.match(/^\/sales\/inbox\/([^/]+)\/?$/i);if(K)return["thread_id",decodeURIComponent(K[1])];const $=J.pathname.match(/^\/sales\/lead\/([^,/]+),([^,/]+),([^/]+)\/?$/i);if($){const V=`urn:li:fs_salesProfile:(${decodeURIComponent($[1])},${decodeURIComponent($[2])},${decodeURIComponent($[3])})`;if(!C(V))throw new H("Sales Navigator lead URL must contain resolved profileId, authType, and authToken");return["recipient_urn",V]}}catch(J){if(J instanceof H)throw J}return["name",Y.toLowerCase()]}function D(Q){return Q?`https://www.linkedin.com/sales/inbox/${encodeURIComponent(Q)}`:""}function L(Q,Y){return`${f}/${encodeURIComponent(Q)}?decoration=${S(W)}&count=1&messageCount=${Y}`}function E(Q){return X(Q?.fullName||[Q?.firstName,Q?.lastName].filter(Boolean).join(" "))}function U(Q){const Y=Q?.participantsResolutionResults||{},J=Array.isArray(Q?.participants)?Q.participants:Object.keys(Y),K=new Map;for(const $ of J){const V=Y[$]||{entityUrn:$};K.set($,V)}return K}function _(Q){if(!Q||typeof Q!=="object")throw new O("Sales Navigator messaging thread API returned malformed payload");const Y=X(Q?.id||"");if(!Y)throw new O("Sales Navigator messaging thread API returned a thread without id");if(!Array.isArray(Q?.messages))throw new O("Sales Navigator messaging thread API returned malformed messages");const J=U(Q),$=Q.messages.map((V)=>{if(!V||typeof V!=="object")throw new O("Sales Navigator messaging thread API returned malformed message row");const B=Number(V?.deliveredAt||0),Z=J.get(V?.author);return{message_id:X(V?.id||""),thread_id:Y,sender:E(Z)||X(V?.author||""),sender_urn:X(V?.author||""),text:X(V?.body||V?.systemMessageContent||""),subject:X(V?.subject||""),timestamp:B?new Date(B).toISOString():"",delivered_at:B||"",type:X(V?.type||"")}}).filter((V)=>V.text||V.subject||V.message_id);$.sort((V,B)=>Number(V.delivered_at||0)-Number(B.delivered_at||0));return $.map((V,B)=>({index:B,...V}))}function z(Q,Y){if(!Q||!Y)return!1;const[J,K]=Y;if(J==="thread_id")return Q.thread_id===K;if(J==="recipient_urn")return(Q.participants||[]).some(($)=>X($.entity_urn)===K);if(J==="name"){const $=X(K).toLowerCase();if(!$)return!1;if(X(Q.person_name).toLowerCase()===$)return!0;return(Q.participants||[]).some((V)=>X(V.name).toLowerCase()===$)}return!1}async function c(Q,Y,{maxPages:J=30}={}){const K=q(Y);if(K[0]==="empty")throw new H("thread or recipient is required");if(K[0]==="thread_id")return K[1];const V=(await v(Q,{limit:500,maxPages:J})).find((B)=>z(B,K));if(!V)throw new y("linkedin salesnav-thread",`No Sales Navigator thread matched ${Y}`);return V.thread_id}async function u(Q,Y,J,K=k){let $=P;if(K<$)$=K;let V=null;for(let F=0;F<30;F+=1){V=await T(Q,Y,L(J,$),"Sales Navigator messaging thread API");const j=Number(V?.totalMessageCount||0),N=Array.isArray(V?.messages)?V.messages.length:0;if(N>=K||j&&N>=j||$>=K)break;let G=$+P;if(j&&j>G)G=j;if(G>K)G=K;$=G}const B=Number(V?.totalMessageCount||0),Z=Array.isArray(V?.messages)?V.messages.length:0;if(B&&Z<B&&Z<K)throw new O(`Sales Navigator messaging thread API returned partial history (${Z}/${B})`);return V}R({site:"linkedin",name:"salesnav-thread",access:"read",description:"Return full Sales Navigator message history for a thread id, Sales Navigator inbox URL, lead URL, recipient urn, or exact recipient name",domain:A,strategy:M.UI,browser:!0,args:[{name:"thread-or-recipient",type:"string",required:!0,positional:!0,help:"Sales Navigator inbox URL/thread id, Sales Navigator lead URL, recipient urn, or exact participant name"},{name:"limit",type:"number",default:k,help:"Maximum messages to return (1-500)"},{name:"max-pages",type:"number",default:30,help:"Maximum inbox pages to scan when resolving a recipient"}],columns:["index","thread_id","thread_url","sender","text","timestamp","subject","message_id","sender_urn","delivered_at","type","total_message_count"],func:async(Q,Y)=>{if(!Q)throw new O("Browser session required for linkedin salesnav-thread");const J=X(Y["thread-or-recipient"]);if(!J)throw new H("thread-or-recipient is required");const K=b(Y.limit,k),$=b(Y["max-pages"],30);await Q.goto(w);await Q.wait(4);const V=await c(Q,J,{maxPages:$}),B=await x(Q),Z=await u(Q,B,V,K),F=_(Z).slice(0,K);if(F.length===0)throw new y("linkedin salesnav-thread",`No messages found for ${V}`);return F.map((j)=>({...j,thread_url:D(V),total_message_count:Number(Z?.totalMessageCount||F.length)}))}});export const __test__={parseThreadInput:q,threadApiUrl:L,participantIndex:U,parseSalesnavThreadMessages:_,threadMatchesInput:z,salesnavThreadUrl:D};
1
+ import{cli as R,Strategy as x}from"@jackwener/opencli/registry";import{ArgumentError as f,CommandExecutionError as l,EmptyResultError as w}from"@jackwener/opencli/errors";import{THREAD_DECORATION as C,THREADS_BASE as U,encodeRestliDecoration as L,fetchInboxRows as E,fetchSalesnavJson as k,getCsrf as P,normalizeWhitespace as o,parseLimit as g}from"./salesnav-inbox.js";const T="www.linkedin.com",M="https://www.linkedin.com/sales/inbox/",h=200,_=20;function D(e){const r=String(e||"").toLowerCase();return r==="linkedin.com"||r.endsWith(".linkedin.com")}function y(e){const r=o(e),a=r.match(/^urn:li:fs_salesProfile:\(([^,()]+),([^,()]+),([^,()]+)\)$/);if(!a)return"";if([a[1],a[2],a[3]].map((n)=>o(n).toLowerCase()).some((n)=>!n||n==="undefined"||n==="null"||n==="not_available"))return"";return r}function b(e){const r=o(e);if(!r)return["empty",""];if(/^2-[A-Za-z0-9+/=_-]+$/.test(r))return["thread_id",r];if(/^urn:li:fs_salesProfile:\(/.test(r)){const a=y(r);if(!a)throw new f("Sales Navigator recipient urn must be urn:li:fs_salesProfile:(profileId,authType,authToken)");return["recipient_urn",a]}try{const a=new URL(r);if(a.protocol!=="https:"||a.username||a.password||a.port||!D(a.hostname))return["name",r.toLowerCase()];const s=a.pathname.match(/^\/sales\/inbox\/([^/]+)\/?$/i);if(s)return["thread_id",decodeURIComponent(s[1])];const n=a.pathname.match(/^\/sales\/lead\/([^,/]+),([^,/]+),([^/]+)\/?$/i);if(n){const t=`urn:li:fs_salesProfile:(${decodeURIComponent(n[1])},${decodeURIComponent(n[2])},${decodeURIComponent(n[3])})`;if(!y(t))throw new f("Sales Navigator lead URL must contain resolved profileId, authType, and authToken");return["recipient_urn",t]}}catch(a){if(a instanceof f)throw a}return["name",r.toLowerCase()]}function v(e){return e?`https://www.linkedin.com/sales/inbox/${encodeURIComponent(e)}`:""}function I(e,r){return`${U}/${encodeURIComponent(e)}?decoration=${L(C)}&count=1&messageCount=${r}`}function j(e){return o(e?.fullName||[e?.firstName,e?.lastName].filter(Boolean).join(" "))}function N(e){const r=e?.participantsResolutionResults||{},a=Array.isArray(e?.participants)?e.participants:Object.keys(r),s=new Map;for(const n of a){const t=r[n]||{entityUrn:n};s.set(n,t)}return s}function A(e){if(!e||typeof e!=="object")throw new l("Sales Navigator messaging thread API returned malformed payload");const r=o(e?.id||"");if(!r)throw new l("Sales Navigator messaging thread API returned a thread without id");if(!Array.isArray(e?.messages))throw new l("Sales Navigator messaging thread API returned malformed messages");const a=N(e),n=e.messages.map((t)=>{if(!t||typeof t!=="object")throw new l("Sales Navigator messaging thread API returned malformed message row");const i=Number(t?.deliveredAt||0),c=a.get(t?.author);return{message_id:o(t?.id||""),thread_id:r,sender:j(c)||o(t?.author||""),sender_urn:o(t?.author||""),text:o(t?.body||t?.systemMessageContent||""),subject:o(t?.subject||""),timestamp:i?new Date(i).toISOString():"",delivered_at:i||"",type:o(t?.type||"")}}).filter((t)=>t.text||t.subject||t.message_id);n.sort((t,i)=>Number(t.delivered_at||0)-Number(i.delivered_at||0));return n.map((t,i)=>({index:i,...t}))}function S(e,r){if(!e||!r)return!1;const[a,s]=r;if(a==="thread_id")return e.thread_id===s;if(a==="recipient_urn")return(e.participants||[]).some((n)=>o(n.entity_urn)===s);if(a==="name"){const n=o(s).toLowerCase();if(!n)return!1;if(o(e.person_name).toLowerCase()===n)return!0;return(e.participants||[]).some((t)=>o(t.name).toLowerCase()===n)}return!1}async function q(e,r,{maxPages:a=30}={}){const s=b(r);if(s[0]==="empty")throw new f("thread or recipient is required");if(s[0]==="thread_id")return s[1];const t=(await E(e,{limit:500,maxPages:a})).find((i)=>S(i,s));if(!t)throw new w("linkedin salesnav-thread",`No Sales Navigator thread matched ${r}`);return t.thread_id}async function O(e,r,a,s=h){let n=_;if(s<n)n=s;let t=null;for(let u=0;u<30;u+=1){t=await k(e,r,I(a,n),"Sales Navigator messaging thread API");const d=Number(t?.totalMessageCount||0),p=Array.isArray(t?.messages)?t.messages.length:0;if(p>=s||d&&p>=d||n>=s)break;let m=n+_;if(d&&d>m)m=d;if(m>s)m=s;n=m}const i=Number(t?.totalMessageCount||0),c=Array.isArray(t?.messages)?t.messages.length:0;if(i&&c<i&&c<s)throw new l(`Sales Navigator messaging thread API returned partial history (${c}/${i})`);return t}R({site:"linkedin",name:"salesnav-thread",access:"read",description:"Return full Sales Navigator message history for a thread id, Sales Navigator inbox URL, lead URL, recipient urn, or exact recipient name",domain:T,strategy:x.UI,browser:!0,args:[{name:"thread-or-recipient",type:"string",required:!0,positional:!0,help:"Sales Navigator inbox URL/thread id, Sales Navigator lead URL, recipient urn, or exact participant name"},{name:"limit",type:"number",default:h,help:"Maximum messages to return (1-500)"},{name:"max-pages",type:"number",default:30,help:"Maximum inbox pages to scan when resolving a recipient"}],columns:["index","thread_id","thread_url","sender","text","timestamp","subject","message_id","sender_urn","delivered_at","type","total_message_count"],func:async(e,r)=>{if(!e)throw new l("Browser session required for linkedin salesnav-thread");const a=o(r["thread-or-recipient"]);if(!a)throw new f("thread-or-recipient is required");const s=g(r.limit,h),n=g(r["max-pages"],30);await e.goto(M);await e.wait(4);const t=await q(e,a,{maxPages:n}),i=await P(e),c=await O(e,i,t,s),u=A(c).slice(0,s);if(u.length===0)throw new w("linkedin salesnav-thread",`No messages found for ${t}`);return u.map((d)=>({...d,thread_url:v(t),total_message_count:Number(c?.totalMessageCount||u.length)}))}});export const __test__={parseThreadInput:b,threadApiUrl:I,participantIndex:N,parseSalesnavThreadMessages:A,threadMatchesInput:S,salesnavThreadUrl:v};
@@ -1,8 +1,8 @@
1
- import{AuthRequiredError as X,CommandExecutionError as Z}from"@jackwener/opencli/errors";import{unwrapEvaluateResult as $}from"./shared.js";export const SEARCH_CLUSTERS_QUERY_ID="voyagerSearchDashClusters.ef3d0937fb65bd7812e32e5a85028e79";function P({keywords:z,filters:F,start:K,count:N}){const O=z?`keywords:${encodeURIComponent(z)},`:"",J=`List(${F.join(",")})`;return`(start:${K},count:${N},origin:GLOBAL_SEARCH_HEADER,query:(${O}flagshipSearchIntent:SEARCH_SRP,queryParameters:${J},includeFiltersInResponse:false))`}function x(z,F){return`(async () => {
1
+ import{AuthRequiredError as u,CommandExecutionError as l}from"@jackwener/opencli/errors";import{unwrapEvaluateResult as y}from"./shared.js";export const SEARCH_CLUSTERS_QUERY_ID="voyagerSearchDashClusters.ef3d0937fb65bd7812e32e5a85028e79";function a({keywords:t,filters:n,start:s,count:i}){const o=t?`keywords:${encodeURIComponent(t)},`:"",r=`List(${n.join(",")})`;return`(start:${s},count:${i},origin:GLOBAL_SEARCH_HEADER,query:(${o}flagshipSearchIntent:SEARCH_SRP,queryParameters:${r},includeFiltersInResponse:false))`}function m(t,n){return`(async () => {
2
2
  const norm = (s) => String(s == null ? '' : s).replace(/[ ]+/g, ' ').replace(/\\s+/g, ' ').trim();
3
3
  const csrf = ((document.cookie.split('; ').find((c) => c.startsWith('JSESSIONID=')) || '').split('=')[1] || '').replace(/^"|"$/g, '');
4
4
  if (!csrf) return { ok: false, auth: true };
5
- const url = '/voyager/api/graphql?queryId=' + ${JSON.stringify(F)} + '&variables=' + ${JSON.stringify(z)};
5
+ const url = '/voyager/api/graphql?queryId=' + ${JSON.stringify(n)} + '&variables=' + ${JSON.stringify(t)};
6
6
  const res = await fetch(url, { credentials: 'include', headers: {
7
7
  'csrf-token': csrf,
8
8
  'accept': 'application/vnd.linkedin.normalized+json+2.1',
@@ -39,4 +39,4 @@ import{AuthRequiredError as X,CommandExecutionError as Z}from"@jackwener/opencli
39
39
  }
40
40
  const paging = clusters.paging || {};
41
41
  return { ok: true, rows, total: paging.total || 0 };
42
- })()`}export async function fetchSearchClusters(z,{keywords:F="",filters:K=[],start:N=0,count:O=10},J){const W=P({keywords:F,filters:K,start:N,count:O}),B=$(await z.evaluate(x(W,SEARCH_CLUSTERS_QUERY_ID)));if(B?.auth)throw new X("linkedin.com",`LinkedIn ${J} requires an active signed-in browser session`);if(!B?.ok)throw new Z(`LinkedIn ${J}: search API returned HTTP ${B?.status||"?"}`);return{rows:Array.isArray(B.rows)?B.rows:[],total:Number(B.total)||0}}export const __test__={buildVariables:P,SEARCH_CLUSTERS_QUERY_ID};
42
+ })()`}export async function fetchSearchClusters(t,{keywords:n="",filters:s=[],start:i=0,count:o=10},r){const c=a({keywords:n,filters:s,start:i,count:o}),e=y(await t.evaluate(m(c,SEARCH_CLUSTERS_QUERY_ID)));if(e?.auth)throw new u("linkedin.com",`LinkedIn ${r} requires an active signed-in browser session`);if(!e?.ok)throw new l(`LinkedIn ${r}: search API returned HTTP ${e?.status||"?"}`);return{rows:Array.isArray(e.rows)?e.rows:[],total:Number(e.total)||0}}export const __test__={buildVariables:a,SEARCH_CLUSTERS_QUERY_ID};
@@ -1,14 +1,14 @@
1
- import{cli as w,Strategy as A}from"@jackwener/opencli/registry";import{ArgumentError as q,AuthRequiredError as V,CommandExecutionError as I}from"@jackwener/opencli/errors";const O="linkedin.com",v=1,k=100,E=0,S={internship:"1",entry:"2","entry-level":"2",associate:"3",mid:"4",senior:"4","mid-senior":"4","mid-senior-level":"4",director:"5",executive:"6"},N={"full-time":"F",fulltime:"F",full:"F","part-time":"P",parttime:"P",part:"P",contract:"C",temporary:"T",temp:"T",volunteer:"V",internship:"I",other:"O"},D={any:"on",month:"r2592000","past-month":"r2592000",week:"r604800","past-week":"r604800",day:"r86400","24h":"r86400","past-24h":"r86400"},L={onsite:"1","on-site":"1",hybrid:"3",remote:"2"};function P(G){if(G===void 0||G===null||G==="")return[];return String(G).split(",").map((Z)=>Z.trim()).filter(Boolean)}function F(G,Z,z){const H=P(G).map((Q)=>{const U=Q.toLowerCase(),W=Z[U];if(!W)throw new q(`Unsupported ${z}: ${Q}`);return W});return[...new Set(H)]}function b(G){return String(G??"").replace(/\s+/g," ").trim()}function R(G,Z,z,$,H=1/0){if(G===void 0||G===null||G==="")return z;const Q=Number(G);if(!Number.isFinite(Q)||!Number.isInteger(Q))throw new q(`${Z} must be an integer, got ${JSON.stringify(G)}`);if(Q<$||Q>H){const U=Number.isFinite(H)?`between ${$} and ${H}`:`at least ${$}`;throw new q(`${Z} must be ${U}, got ${Q}`)}return Q}function T(G){if(!G)return"";try{const Z=new URL(G);if(Z.pathname==="/redir/redirect/")return Z.searchParams.get("url")||G}catch{}return G}function m(G){const z=["origin:"+(G.companyIds.length||G.experienceLevels.length||G.jobTypes.length||G.datePostedValues.length||G.remoteTypes.length?"JOB_SEARCH_PAGE_JOB_FILTER":"JOB_SEARCH_PAGE_OTHER_ENTRY"),"keywords:"+G.keywords];if(G.location)z.push("locationUnion:(seoLocation:(location:"+G.location+"))");const $=[];if(G.companyIds.length)$.push("company:List("+G.companyIds.join(",")+")");if(G.experienceLevels.length)$.push("experience:List("+G.experienceLevels.join(",")+")");if(G.jobTypes.length)$.push("jobType:List("+G.jobTypes.join(",")+")");if(G.datePostedValues.length)$.push("timePostedRange:List("+G.datePostedValues.join(",")+")");if(G.remoteTypes.length)$.push("workplaceType:List("+G.remoteTypes.join(",")+")");if($.length)z.push("selectedFilters:("+$.join(",")+")");z.push("spellCorrectionEnabled:true");return"("+z.join(",")+")"}function c(G,Z,z){const $=new URLSearchParams({decorationId:"com.linkedin.voyager.dash.deco.jobs.search.JobSearchCardsCollection-220",count:String(z),q:"jobSearch"}),H=encodeURIComponent(m(G)).replace(/%3A/gi,":").replace(/%2C/gi,",").replace(/%28/gi,"(").replace(/%29/gi,")");return"/voyager/api/voyagerJobsDashJobCards?"+$.toString()+"&query="+H+"&start="+Z}function _(G){const Z=String(G??"").replace(/\s+/g," ").trim().toLowerCase();if(!Z)return!1;return/\b(sign in|log in|join linkedin)\b/.test(Z)||/linkedin\.com\/(login|checkpoint|authwall)/i.test(Z)||/\b(captcha|verification required)\b/.test(Z)||/(请登录|登录领英|安全验证)/.test(Z)}function g(){return`(() => {
1
+ import{cli as q,Strategy as P}from"@jackwener/opencli/registry";import{ArgumentError as p,AuthRequiredError as y,CommandExecutionError as R}from"@jackwener/opencli/errors";const g="linkedin.com",D=1,O=100,N=0,x={internship:"1",entry:"2","entry-level":"2",associate:"3",mid:"4",senior:"4","mid-senior":"4","mid-senior-level":"4",director:"5",executive:"6"},k={"full-time":"F",fulltime:"F",full:"F","part-time":"P",parttime:"P",part:"P",contract:"C",temporary:"T",temp:"T",volunteer:"V",internship:"I",other:"O"},L={any:"on",month:"r2592000","past-month":"r2592000",week:"r604800","past-week":"r604800",day:"r86400","24h":"r86400","past-24h":"r86400"},j={onsite:"1","on-site":"1",hybrid:"3",remote:"2"};function b(e){if(e===void 0||e===null||e==="")return[];return String(e).split(",").map((t)=>t.trim()).filter(Boolean)}function m(e,t,r){const o=b(e).map((i)=>{const s=i.toLowerCase(),c=t[s];if(!c)throw new p(`Unsupported ${r}: ${i}`);return c});return[...new Set(o)]}function J(e){return String(e??"").replace(/\s+/g," ").trim()}function w(e,t,r,n,o=1/0){if(e===void 0||e===null||e==="")return r;const i=Number(e);if(!Number.isFinite(i)||!Number.isInteger(i))throw new p(`${t} must be an integer, got ${JSON.stringify(e)}`);if(i<n||i>o){const s=Number.isFinite(o)?`between ${n} and ${o}`:`at least ${n}`;throw new p(`${t} must be ${s}, got ${i}`)}return i}function A(e){if(!e)return"";try{const t=new URL(e);if(t.pathname==="/redir/redirect/")return t.searchParams.get("url")||e}catch{}return e}function F(e){const r=["origin:"+(e.companyIds.length||e.experienceLevels.length||e.jobTypes.length||e.datePostedValues.length||e.remoteTypes.length?"JOB_SEARCH_PAGE_JOB_FILTER":"JOB_SEARCH_PAGE_OTHER_ENTRY"),"keywords:"+e.keywords];if(e.location)r.push("locationUnion:(seoLocation:(location:"+e.location+"))");const n=[];if(e.companyIds.length)n.push("company:List("+e.companyIds.join(",")+")");if(e.experienceLevels.length)n.push("experience:List("+e.experienceLevels.join(",")+")");if(e.jobTypes.length)n.push("jobType:List("+e.jobTypes.join(",")+")");if(e.datePostedValues.length)n.push("timePostedRange:List("+e.datePostedValues.join(",")+")");if(e.remoteTypes.length)n.push("workplaceType:List("+e.remoteTypes.join(",")+")");if(n.length)r.push("selectedFilters:("+n.join(",")+")");r.push("spellCorrectionEnabled:true");return"("+r.join(",")+")"}function U(e,t,r){const n=new URLSearchParams({decorationId:"com.linkedin.voyager.dash.deco.jobs.search.JobSearchCardsCollection-220",count:String(r),q:"jobSearch"}),o=encodeURIComponent(F(e)).replace(/%3A/gi,":").replace(/%2C/gi,",").replace(/%28/gi,"(").replace(/%29/gi,")");return"/voyager/api/voyagerJobsDashJobCards?"+n.toString()+"&query="+o+"&start="+t}function T(e){const t=String(e??"").replace(/\s+/g," ").trim().toLowerCase();if(!t)return!1;return/\b(sign in|log in|join linkedin)\b/.test(t)||/linkedin\.com\/(login|checkpoint|authwall)/i.test(t)||/\b(captcha|verification required)\b/.test(t)||/(请登录|登录领英|安全验证)/.test(t)}function B(){return`(() => {
2
2
  const text = [
3
3
  window.location.href || '',
4
4
  document.title || '',
5
5
  document.body ? (document.body.innerText || '').slice(0, 4000) : '',
6
6
  ].join('\\n');
7
- return ${_.toString()}(text);
8
- })()`}async function x(G,Z){if(await G.evaluate(g()))throw new V(O,`${Z} requires an active signed-in LinkedIn browser session`)}function d(G){const Z=new Set,z=[];for(const $ of P(G)){const H=$.replace(/^urn:li:[a-z_]+:/,"");if(/^\d+$/.test(H))Z.add(H);else z.push($)}if(z.length)throw new q(`--company now requires numeric LinkedIn company IDs (got name(s): ${z.join(", ")}). Find an ID from the company's LinkedIn page URL or its /company/<slug>/ Voyager data.`);return[...Z]}async function o(G,Z){const z=25,$=[];let H=Z.start;const U=(await G.getCookies({url:"https://www.linkedin.com"})).find((B)=>B.name==="JSESSIONID")?.value;if(!U)throw new V(O,"LinkedIn JSESSIONID cookie not found. Please sign in to LinkedIn in the browser.");const W=U.replace(/^"|"$/g,"");while($.length<Z.limit){const B=Math.min(z,Z.limit-$.length),Y=c(Z,H,B),X=await G.evaluate(`(async () => {
9
- const res = await fetch(${JSON.stringify(Y)}, {
7
+ return ${T.toString()}(text);
8
+ })()`}async function _(e,t){if(await e.evaluate(B()))throw new y(g,`${t} requires an active signed-in LinkedIn browser session`)}function M(e){const t=new Set,r=[];for(const n of b(e)){const o=n.replace(/^urn:li:[a-z_]+:/,"");if(/^\d+$/.test(o))t.add(o);else r.push(n)}if(r.length)throw new p(`--company now requires numeric LinkedIn company IDs (got name(s): ${r.join(", ")}). Find an ID from the company's LinkedIn page URL or its /company/<slug>/ Voyager data.`);return[...t]}async function V(e,t){const r=25,n=[];let o=t.start;const s=(await e.getCookies({url:"https://www.linkedin.com"})).find((a)=>a.name==="JSESSIONID")?.value;if(!s)throw new y(g,"LinkedIn JSESSIONID cookie not found. Please sign in to LinkedIn in the browser.");const c=s.replace(/^"|"$/g,"");while(n.length<t.limit){const a=Math.min(r,t.limit-n.length),u=U(t,o,a),d=await e.evaluate(`(async () => {
9
+ const res = await fetch(${JSON.stringify(u)}, {
10
10
  credentials: 'include',
11
- headers: { 'csrf-token': ${JSON.stringify(W)}, 'x-restli-protocol-version': '2.0.0' },
11
+ headers: { 'csrf-token': ${JSON.stringify(c)}, 'x-restli-protocol-version': '2.0.0' },
12
12
  });
13
13
  if (res.status === 401 || res.status === 403) {
14
14
  const text = await res.text();
@@ -22,14 +22,14 @@ import{cli as w,Strategy as A}from"@jackwener/opencli/registry";import{ArgumentE
22
22
  return { error: 'LinkedIn API error: HTTP ' + res.status + ' ' + text.slice(0, 200) };
23
23
  }
24
24
  return res.json();
25
- })()`);if(!X||X.error){if(X?.authRequired)throw new V(O,X.error);throw new I(X?.error||"LinkedIn search returned an unexpected response")}const C=Array.isArray(X?.elements)?X.elements:[];if(C.length===0)break;for(const j of C){const K=j?.jobCardUnion?.jobPostingCard;if(!K)continue;const y=[K.jobPostingUrn,K.jobPosting?.entityUrn,K.entityUrn].filter(Boolean).map((J)=>String(J).match(/(\d+)/)?.[1]).find(Boolean)??"",M=(K.footerItems||[]).find((J)=>J?.type==="LISTED_DATE"&&J?.timeAt),h=M?.timeAt?new Date(M.timeAt).toISOString().slice(0,10):"";$.push({title:K.jobPostingTitle||K.title?.text||"",company:K.primaryDescription?.text||"",location:K.secondaryDescription?.text||"",listed:h,salary:K.tertiaryDescription?.text||"",url:y?"https://www.linkedin.com/jobs/view/"+y:""})}if(C.length<B)break;H+=C.length}return $.slice(0,Z.limit).map((B,Y)=>({rank:Z.start+Y+1,...B}))}async function f(G,Z){const z=[];for(let $=0;$<Z.length;$++){const H=Z[$];console.error(`[ppcli:linkedin] Fetching details ${$+1}/${Z.length}: ${H.title}`);if(!H.url){const Q="no url";console.error(`[ppcli:linkedin] Skipping detail for "${H.title}": ${Q}`);z.push({...H,description:null,apply_url:null,detail_error:Q});continue}try{await G.goto(H.url);await x(G,"LinkedIn job detail");await G.wait({text:"About the job",timeout:8});await G.evaluate(`(() => {
25
+ })()`);if(!d||d.error){if(d?.authRequired)throw new y(g,d.error);throw new R(d?.error||"LinkedIn search returned an unexpected response")}const h=Array.isArray(d?.elements)?d.elements:[];if(h.length===0)break;for(const v of h){const l=v?.jobCardUnion?.jobPostingCard;if(!l)continue;const I=[l.jobPostingUrn,l.jobPosting?.entityUrn,l.entityUrn].filter(Boolean).map((f)=>String(f).match(/(\d+)/)?.[1]).find(Boolean)??"",S=(l.footerItems||[]).find((f)=>f?.type==="LISTED_DATE"&&f?.timeAt),E=S?.timeAt?new Date(S.timeAt).toISOString().slice(0,10):"";n.push({title:l.jobPostingTitle||l.title?.text||"",company:l.primaryDescription?.text||"",location:l.secondaryDescription?.text||"",listed:E,salary:l.tertiaryDescription?.text||"",url:I?"https://www.linkedin.com/jobs/view/"+I:""})}if(h.length<a)break;o+=h.length}return n.slice(0,t.limit).map((a,u)=>({rank:t.start+u+1,...a}))}async function C(e,t){const r=[];for(let n=0;n<t.length;n++){const o=t[n];console.error(`[ppcli:linkedin] Fetching details ${n+1}/${t.length}: ${o.title}`);if(!o.url){const i="no url";console.error(`[ppcli:linkedin] Skipping detail for "${o.title}": ${i}`);r.push({...o,description:null,apply_url:null,detail_error:i});continue}try{await e.goto(o.url);await _(e,"LinkedIn job detail");await e.wait({text:"About the job",timeout:8});await e.evaluate(`(() => {
26
26
  const norm = (v) => (v || '').replace(/\\s+/g, ' ').trim().toLowerCase();
27
27
  const section = [...document.querySelectorAll('div, section, article')]
28
28
  .find(el => norm(el.querySelector('h1,h2,h3,h4')?.textContent || '') === 'about the job');
29
29
  const btn = [...(section?.querySelectorAll('button, a[role="button"]') || [])]
30
30
  .find(el => /more/.test(norm(el.textContent || '')) || /more/.test(norm(el.getAttribute('aria-label') || '')));
31
31
  if (btn) btn.click();
32
- })()`);await G.wait(1);const Q=await G.evaluate(`(() => {
32
+ })()`);await e.wait(1);const i=await e.evaluate(`(() => {
33
33
  const norm = (v) => (v || '').replace(/\\s+/g, ' ').trim();
34
34
  // Find the most specific (shortest) container with "About the job" heading
35
35
  // Shortest = most specific DOM node, avoiding outer wrappers that include unrelated text
@@ -47,4 +47,4 @@ import{cli as w,Strategy as A}from"@jackwener/opencli/registry";import{ArgumentE
47
47
  .find(a => /apply/i.test(a.text) || /apply/i.test(a.aria));
48
48
 
49
49
  return { description, applyUrl: applyLink?.href || '' };
50
- })()`),U=b(Q?.description),W=T(String(Q?.applyUrl??"")),B=U?null:"missing description";z.push({...H,description:U||null,apply_url:W||null,detail_error:B})}catch(Q){if(Q instanceof V)throw Q;const U=`fetch failed: ${Q?.message||Q}`;console.error(`[ppcli:linkedin] Detail fetch failed for ${H.url}: ${U}`);z.push({...H,description:null,apply_url:null,detail_error:U})}}return z}w({site:"linkedin",name:"search",access:"read",description:"Search LinkedIn jobs",domain:"www.linkedin.com",strategy:A.COOKIE,browser:!0,args:[{name:"query",type:"string",required:!0,positional:!0,help:"Job search keywords"},{name:"location",type:"string",required:!1,help:"Location text such as San Francisco Bay Area"},{name:"limit",type:"int",default:10,help:"Number of jobs to return (max 100)"},{name:"start",type:"int",default:0,help:"Result offset for pagination"},{name:"details",type:"bool",default:!1,help:"Include full job description and apply URL (slower)"},{name:"company",type:"string",required:!1,help:"Comma-separated company names or LinkedIn company IDs"},{name:"experience-level",type:"string",required:!1,help:"Comma-separated: internship, entry, associate, mid-senior, director, executive"},{name:"job-type",type:"string",required:!1,help:"Comma-separated: full-time, part-time, contract, temporary, volunteer, internship, other"},{name:"date-posted",type:"string",required:!1,help:"One of: any, month, week, 24h"},{name:"remote",type:"string",required:!1,help:"Comma-separated: on-site, hybrid, remote"}],columns:["rank","title","company","location","listed","salary","url"],func:async(G,Z)=>{const z=R(Z.limit,"--limit",10,v,k),$=R(Z.start,"--start",0,E),H=Boolean(Z.details),Q=(Z.location??"").trim(),U=String(Z.query??"").trim();if(!U)throw new q("query is required");await G.goto("https://www.linkedin.com/jobs/");await G.wait(2);const W=d(Z.company),B={keywords:U,location:Q,limit:z,start:$,companyIds:W,experienceLevels:F(Z["experience-level"],S,"experience_level"),jobTypes:F(Z["job-type"],N,"job_type"),datePostedValues:F(Z["date-posted"],D,"date_posted"),remoteTypes:F(Z.remote,L,"remote")},Y=await o(G,B);if(!H)return Y;return f(G,Y)}});export const __test__={parseCsvArg:P,parseIntegerArg:R,mapFilterValues:F,decodeLinkedinRedirect:T,looksLinkedInAuthWallText:_,assertLinkedInAuthenticated:x,enrichJobDetails:f,EXPERIENCE_LEVELS:S,JOB_TYPES:N,DATE_POSTED:D,REMOTE_TYPES:L};
50
+ })()`),s=J(i?.description),c=A(String(i?.applyUrl??"")),a=s?null:"missing description";r.push({...o,description:s||null,apply_url:c||null,detail_error:a})}catch(i){if(i instanceof y)throw i;const s=`fetch failed: ${i?.message||i}`;console.error(`[ppcli:linkedin] Detail fetch failed for ${o.url}: ${s}`);r.push({...o,description:null,apply_url:null,detail_error:s})}}return r}q({site:"linkedin",name:"search",access:"read",description:"Search LinkedIn jobs",domain:"www.linkedin.com",strategy:P.COOKIE,browser:!0,args:[{name:"query",type:"string",required:!0,positional:!0,help:"Job search keywords"},{name:"location",type:"string",required:!1,help:"Location text such as San Francisco Bay Area"},{name:"limit",type:"int",default:10,help:"Number of jobs to return (max 100)"},{name:"start",type:"int",default:0,help:"Result offset for pagination"},{name:"details",type:"bool",default:!1,help:"Include full job description and apply URL (slower)"},{name:"company",type:"string",required:!1,help:"Comma-separated company names or LinkedIn company IDs"},{name:"experience-level",type:"string",required:!1,help:"Comma-separated: internship, entry, associate, mid-senior, director, executive"},{name:"job-type",type:"string",required:!1,help:"Comma-separated: full-time, part-time, contract, temporary, volunteer, internship, other"},{name:"date-posted",type:"string",required:!1,help:"One of: any, month, week, 24h"},{name:"remote",type:"string",required:!1,help:"Comma-separated: on-site, hybrid, remote"}],columns:["rank","title","company","location","listed","salary","url"],func:async(e,t)=>{const r=w(t.limit,"--limit",10,D,O),n=w(t.start,"--start",0,N),o=Boolean(t.details),i=(t.location??"").trim(),s=String(t.query??"").trim();if(!s)throw new p("query is required");await e.goto("https://www.linkedin.com/jobs/");await e.wait(2);const c=M(t.company),a={keywords:s,location:i,limit:r,start:n,companyIds:c,experienceLevels:m(t["experience-level"],x,"experience_level"),jobTypes:m(t["job-type"],k,"job_type"),datePostedValues:m(t["date-posted"],L,"date_posted"),remoteTypes:m(t.remote,j,"remote")},u=await V(e,a);if(!o)return u;return C(e,u)}});export const __test__={parseCsvArg:b,parseIntegerArg:w,mapFilterValues:m,decodeLinkedinRedirect:A,looksLinkedInAuthWallText:T,assertLinkedInAuthenticated:_,enrichJobDetails:C,EXPERIENCE_LEVELS:x,JOB_TYPES:k,DATE_POSTED:L,REMOTE_TYPES:j};
@@ -1,4 +1,4 @@
1
- import{ArgumentError as F}from"@jackwener/opencli/errors";export const NORM_COMMENT_DECORATION="com.linkedin.voyager.dash.deco.social.NormComment-43",REACTION_CREATE_QID="voyagerSocialDashReactions.b731222600772fd42464c0fe19bd722b",REACTION_DELETE_QID="voyagerSocialDashReactions.f68b48ae5bc0085d7a45c7003b772a39",REPOST_CREATE_QID="voyagerFeedDashReposts.a0663ae5c654123343da36617d2dbfde";export function looksLikeCommentUrn(q){const b=String(q??"");return/urn:li:(fsd_)?comment:\(/.test(b)}export const REACTION_TYPES=["LIKE","CELEBRATE","SUPPORT","LOVE","INSIGHTFUL","FUNNY"];const H={like:"LIKE",celebrate:"PRAISE",praise:"PRAISE",support:"EMPATHY",empathy:"EMPATHY",love:"APPRECIATION",appreciation:"APPRECIATION",insightful:"INTEREST",interest:"INTEREST",funny:"ENTERTAINMENT",entertainment:"ENTERTAINMENT",haha:"ENTERTAINMENT"};export function parseReactionType(q){const b=String(q??"like").trim().toLowerCase(),z=H[b];if(!z)throw new F(`--reaction 只能是 like / celebrate / support / love / insightful / funny(收到 "${q}")`);return z}export function normalizeThreadUrn(q){const b=String(q??"").trim();if(!b)throw new F("post 标识必填(帖子 URL 或 urn:li:activity:… / urn:li:ugcPost:…)");const z=b.match(/urn:li:(activity|ugcPost|share):(\d+)/);if(z)return`urn:li:${z[1]}:${z[2]}`;const D=b.match(/activity[:\-](\d{6,})/i);if(D)return`urn:li:activity:${D[1]}`;const G=b.match(/ugcPost[:\-](\d{6,})/i);if(G)return`urn:li:ugcPost:${G[1]}`;throw new F(`无法从 "${b}" 解析出帖子 urn(需 activity/ugcPost urn 或含 activity-<id> 的 LinkedIn 链接)`)}export function normalizeCommentUrn(q){const b=String(q??"").trim();if(!b)throw new F("comment 标识必填(urn:li:comment:(…) 或 urn:li:fsd_comment:(…))");const z=b.match(/urn:li:comment:\((activity|ugcPost):(\d+),(\d+)\)/);if(z)return`urn:li:comment:(${z[1]}:${z[2]},${z[3]})`;const D=b.match(/urn:li:fsd_comment:\((\d+),urn:li:(activity|ugcPost):(\d+)\)/);if(D)return`urn:li:comment:(${D[2]}:${D[3]},${D[1]})`;throw new F(`无法解析评论 urn "${b}"(需 urn:li:comment:(…) 或 urn:li:fsd_comment:(…);可从 linkedin post-comments 的 comment_urn 列直接取)`)}export const SOCIAL_PREAMBLE=String.raw`
1
+ import{ArgumentError as a}from"@jackwener/opencli/errors";export const NORM_COMMENT_DECORATION="com.linkedin.voyager.dash.deco.social.NormComment-43",REACTION_CREATE_QID="voyagerSocialDashReactions.b731222600772fd42464c0fe19bd722b",REACTION_DELETE_QID="voyagerSocialDashReactions.f68b48ae5bc0085d7a45c7003b772a39",REPOST_CREATE_QID="voyagerFeedDashReposts.a0663ae5c654123343da36617d2dbfde";export function looksLikeCommentUrn(e){const t=String(e??"");return/urn:li:(fsd_)?comment:\(/.test(t)}export const REACTION_TYPES=["LIKE","CELEBRATE","SUPPORT","LOVE","INSIGHTFUL","FUNNY"];const s={like:"LIKE",celebrate:"PRAISE",praise:"PRAISE",support:"EMPATHY",empathy:"EMPATHY",love:"APPRECIATION",appreciation:"APPRECIATION",insightful:"INTEREST",interest:"INTEREST",funny:"ENTERTAINMENT",entertainment:"ENTERTAINMENT",haha:"ENTERTAINMENT"};export function parseReactionType(e){const t=String(e??"like").trim().toLowerCase(),n=s[t];if(!n)throw new a(`--reaction 只能是 like / celebrate / support / love / insightful / funny(收到 "${e}")`);return n}export function normalizeThreadUrn(e){const t=String(e??"").trim();if(!t)throw new a("post 标识必填(帖子 URL 或 urn:li:activity:… / urn:li:ugcPost:…)");const n=t.match(/urn:li:(activity|ugcPost|share):(\d+)/);if(n)return`urn:li:${n[1]}:${n[2]}`;const r=t.match(/activity[:\-](\d{6,})/i);if(r)return`urn:li:activity:${r[1]}`;const o=t.match(/ugcPost[:\-](\d{6,})/i);if(o)return`urn:li:ugcPost:${o[1]}`;throw new a(`无法从 "${t}" 解析出帖子 urn(需 activity/ugcPost urn 或含 activity-<id> 的 LinkedIn 链接)`)}export function normalizeCommentUrn(e){const t=String(e??"").trim();if(!t)throw new a("comment 标识必填(urn:li:comment:(…) 或 urn:li:fsd_comment:(…))");const n=t.match(/urn:li:comment:\((activity|ugcPost):(\d+),(\d+)\)/);if(n)return`urn:li:comment:(${n[1]}:${n[2]},${n[3]})`;const r=t.match(/urn:li:fsd_comment:\((\d+),urn:li:(activity|ugcPost):(\d+)\)/);if(r)return`urn:li:comment:(${r[2]}:${r[3]},${r[1]})`;throw new a(`无法解析评论 urn "${t}"(需 urn:li:comment:(…) 或 urn:li:fsd_comment:(…);可从 linkedin post-comments 的 comment_urn 列直接取)`)}export const SOCIAL_PREAMBLE=String.raw`
2
2
  const jsessionRaw = (document.cookie.split('; ').find((c) => c.startsWith('JSESSIONID=')) || '').split('=')[1] || '';
3
3
  const csrf = jsessionRaw.replace(/^"|"$/g, '');
4
4
  if (!csrf) return { ok: false, stage: 'auth', error: 'JSESSIONID_missing' };
@@ -9,11 +9,11 @@ import{ArgumentError as F}from"@jackwener/opencli/errors";export const NORM_COMM
9
9
  'x-li-lang': 'en_US',
10
10
  'content-type': 'application/json; charset=UTF-8',
11
11
  };
12
- `;export function buildReactScript({threadUrn:q,reactionType:b,remove:z}){return`(async () => {
12
+ `;export function buildReactScript({threadUrn:e,reactionType:t,remove:n}){return`(async () => {
13
13
  ${SOCIAL_PREAMBLE}
14
- const THREAD = ${JSON.stringify(q)};
15
- const REMOVE = ${JSON.stringify(Boolean(z))};
16
- const REACTION = ${JSON.stringify(b)};
14
+ const THREAD = ${JSON.stringify(e)};
15
+ const REMOVE = ${JSON.stringify(Boolean(n))};
16
+ const REACTION = ${JSON.stringify(t)};
17
17
  if (REMOVE) {
18
18
  const res = await fetch('/voyager/api/voyagerSocialDashReactions?action=deleteReaction', {
19
19
  method: 'POST', credentials: 'include', headers: H,
@@ -28,15 +28,15 @@ import{ArgumentError as F}from"@jackwener/opencli/errors";export const NORM_COMM
28
28
  });
29
29
  if (res.status === 201 || res.status === 200) return { ok: true, removed: false, reaction: REACTION, httpStatus: res.status };
30
30
  return { ok: false, stage: 'react', httpStatus: res.status, error: (await res.text()).slice(0, 300) };
31
- })()`}export function buildCommentScript({threadUrn:q,text:b,decorationId:z}){return`(async () => {
31
+ })()`}export function buildCommentScript({threadUrn:e,text:t,decorationId:n}){return`(async () => {
32
32
  ${SOCIAL_PREAMBLE}
33
- const THREAD = ${JSON.stringify(q)};
34
- const TEXT = ${JSON.stringify(b)};
33
+ const THREAD = ${JSON.stringify(e)};
34
+ const TEXT = ${JSON.stringify(t)};
35
35
  const payload = {
36
36
  commentary: { text: TEXT, attributesV2: [], $type: 'com.linkedin.voyager.dash.common.text.TextViewModel' },
37
37
  threadUrn: THREAD,
38
38
  };
39
- const res = await fetch('/voyager/api/voyagerSocialDashNormComments?decorationId=' + ${JSON.stringify(z)}, {
39
+ const res = await fetch('/voyager/api/voyagerSocialDashNormComments?decorationId=' + ${JSON.stringify(n)}, {
40
40
  method: 'POST', credentials: 'include', headers: H,
41
41
  body: JSON.stringify(payload),
42
42
  });
@@ -49,9 +49,9 @@ import{ArgumentError as F}from"@jackwener/opencli/errors";export const NORM_COMM
49
49
  const m = body.match(/urn:li:fsd_comment:\\((\\d+),urn:li:(activity|ugcPost):(\\d+)\\)/);
50
50
  if (m) commentUrn = 'urn:li:comment:(' + m[2] + ':' + m[3] + ',' + m[1] + ')';
51
51
  return { ok: true, commentUrn, httpStatus: res.status };
52
- })()`}export function buildPostDetailScript({activityUrn:q}){return`(async () => {
52
+ })()`}export function buildPostDetailScript({activityUrn:e}){return`(async () => {
53
53
  ${SOCIAL_PREAMBLE}
54
- const ACTIVITY = ${JSON.stringify(q)};
54
+ const ACTIVITY = ${JSON.stringify(e)};
55
55
  const res = await fetch('/voyager/api/feed/updates/' + encodeURIComponent(ACTIVITY) + '?commentsCount=0&likesCount=0', { credentials: 'include', headers: H });
56
56
  if (!res.ok) return { ok: false, stage: 'read', httpStatus: res.status, error: (await res.text()).slice(0, 300) };
57
57
  const j = await res.json();
@@ -85,11 +85,11 @@ import{ArgumentError as F}from"@jackwener/opencli/errors";export const NORM_COMM
85
85
  url: perm,
86
86
  },
87
87
  };
88
- })()`}export function buildReadCommentsScript({activityUrn:q,count:b,start:z,sortOrder:D}){return`(async () => {
88
+ })()`}export function buildReadCommentsScript({activityUrn:e,count:t,start:n,sortOrder:r}){return`(async () => {
89
89
  ${SOCIAL_PREAMBLE}
90
- const ACTIVITY = ${JSON.stringify(q)};
91
- const url = '/voyager/api/feed/comments?count=' + ${JSON.stringify(b)} + '&start=' + ${JSON.stringify(z)}
92
- + '&q=comments&sortOrder=' + ${JSON.stringify(D)} + '&updateId=' + encodeURIComponent(ACTIVITY);
90
+ const ACTIVITY = ${JSON.stringify(e)};
91
+ const url = '/voyager/api/feed/comments?count=' + ${JSON.stringify(t)} + '&start=' + ${JSON.stringify(n)}
92
+ + '&q=comments&sortOrder=' + ${JSON.stringify(r)} + '&updateId=' + encodeURIComponent(ACTIVITY);
93
93
  const res = await fetch(url, { credentials: 'include', headers: H });
94
94
  if (!res.ok) return { ok: false, stage: 'read', httpStatus: res.status, error: (await res.text()).slice(0, 300) };
95
95
  const j = await res.json();
@@ -133,14 +133,14 @@ import{ArgumentError as F}from"@jackwener/opencli/errors";export const NORM_COMM
133
133
  });
134
134
  const total = (j.data && j.data.paging && j.data.paging.total) || rows.length;
135
135
  return { ok: true, rows, total };
136
- })()`}export function buildCommentReactScript({commentUrn:q,reactionType:b,remove:z,createQid:D,deleteQid:G}){return`(async () => {
136
+ })()`}export function buildCommentReactScript({commentUrn:e,reactionType:t,remove:n,createQid:r,deleteQid:o}){return`(async () => {
137
137
  ${SOCIAL_PREAMBLE}
138
138
  const GH = Object.assign({}, H, { 'x-li-graphql-pegasus-client': 'true' });
139
- const COMMENT = ${JSON.stringify(q)};
140
- const REMOVE = ${JSON.stringify(Boolean(z))};
141
- const REACTION = ${JSON.stringify(b)};
139
+ const COMMENT = ${JSON.stringify(e)};
140
+ const REMOVE = ${JSON.stringify(Boolean(n))};
141
+ const REACTION = ${JSON.stringify(t)};
142
142
  if (REMOVE) {
143
- const qid = ${JSON.stringify(G)};
143
+ const qid = ${JSON.stringify(o)};
144
144
  const res = await fetch('/voyager/api/graphql?action=execute&queryId=' + qid, {
145
145
  method: 'POST', credentials: 'include', headers: GH,
146
146
  body: JSON.stringify({ variables: { threadUrn: COMMENT }, queryId: qid, includeWebMetadata: true }),
@@ -148,17 +148,17 @@ import{ArgumentError as F}from"@jackwener/opencli/errors";export const NORM_COMM
148
148
  if (res.status === 200 || res.status === 201) return { ok: true, removed: true };
149
149
  return { ok: false, stage: 'unreact_comment', httpStatus: res.status, error: (await res.text()).slice(0, 300) };
150
150
  }
151
- const qid = ${JSON.stringify(D)};
151
+ const qid = ${JSON.stringify(r)};
152
152
  const res = await fetch('/voyager/api/graphql?action=execute&queryId=' + qid, {
153
153
  method: 'POST', credentials: 'include', headers: GH,
154
154
  body: JSON.stringify({ variables: { entity: { reactionType: REACTION }, threadUrn: COMMENT }, queryId: qid, includeWebMetadata: true }),
155
155
  });
156
156
  if (res.status === 200 || res.status === 201) return { ok: true, removed: false, reaction: REACTION };
157
157
  return { ok: false, stage: 'react_comment', httpStatus: res.status, error: (await res.text()).slice(0, 300) };
158
- })()`}export function buildRepostScript({activityUrn:q,commentary:b,repostQid:z}){return`(async () => {
158
+ })()`}export function buildRepostScript({activityUrn:e,commentary:t,repostQid:n}){return`(async () => {
159
159
  ${SOCIAL_PREAMBLE}
160
- const ACTIVITY = ${JSON.stringify(q)};
161
- const COMMENTARY = ${JSON.stringify(b||"")};
160
+ const ACTIVITY = ${JSON.stringify(e)};
161
+ const COMMENTARY = ${JSON.stringify(t||"")};
162
162
  // 1. 解析 shareUrn
163
163
  const u = await fetch('/voyager/api/feed/updates/' + encodeURIComponent(ACTIVITY) + '?commentsCount=0&likesCount=0', { credentials: 'include', headers: H });
164
164
  if (!u.ok) return { ok: false, stage: 'resolve', httpStatus: u.status, error: (await u.text()).slice(0, 200) };
@@ -178,7 +178,7 @@ import{ArgumentError as F}from"@jackwener/opencli/errors";export const NORM_COMM
178
178
  }
179
179
  // 2b. 纯转发 → GraphQL Reposts
180
180
  const GH = Object.assign({}, H, { 'x-li-graphql-pegasus-client': 'true' });
181
- const qid = ${JSON.stringify(z)};
181
+ const qid = ${JSON.stringify(n)};
182
182
  const r = await fetch('/voyager/api/graphql?action=execute&queryId=' + qid, {
183
183
  method: 'POST', credentials: 'include', headers: GH,
184
184
  body: JSON.stringify({ variables: { entity: { rootContentUrn: shareUrn } }, queryId: qid, includeWebMetadata: true }),
@@ -189,10 +189,10 @@ import{ArgumentError as F}from"@jackwener/opencli/errors";export const NORM_COMM
189
189
  const act = (rt.match(/urn:li:activity:[0-9]+/g) || [])[0] || '';
190
190
  const rk = (rt.match(/urn:li:fsd_repost:[^"\\\\]+/) || [])[0] || '';
191
191
  return { ok: true, quote: false, shared_urn: shareUrn, repost_urn: act || rk };
192
- })()`}export function buildNotificationsScript({count:q,start:b,filter:z}){return`(async () => {
192
+ })()`}export function buildNotificationsScript({count:e,start:t,filter:n}){return`(async () => {
193
193
  ${SOCIAL_PREAMBLE}
194
- const url = '/voyager/api/voyagerIdentityDashNotificationCards?q=filterVanityName&filterVanityName=' + ${JSON.stringify(z)}
195
- + '&count=' + ${JSON.stringify(q)} + '&start=' + ${JSON.stringify(b)};
194
+ const url = '/voyager/api/voyagerIdentityDashNotificationCards?q=filterVanityName&filterVanityName=' + ${JSON.stringify(n)}
195
+ + '&count=' + ${JSON.stringify(e)} + '&start=' + ${JSON.stringify(t)};
196
196
  const res = await fetch(url, { credentials: 'include', headers: H });
197
197
  if (!res.ok) return { ok: false, stage: 'read', httpStatus: res.status, error: (await res.text()).slice(0, 300) };
198
198
  const j = await res.json();
@@ -212,10 +212,10 @@ import{ArgumentError as F}from"@jackwener/opencli/errors";export const NORM_COMM
212
212
  });
213
213
  const meta = j.data && j.data.metadata;
214
214
  return { ok: true, rows, numUnseen: (meta && meta.numUnseen) || 0, nextStart: (meta && meta.nextStart) || 0 };
215
- })()`}export function buildFollowScript({target:q,following:b}){return`(async () => {
215
+ })()`}export function buildFollowScript({target:e,following:t}){return`(async () => {
216
216
  ${SOCIAL_PREAMBLE}
217
- const TARGET = ${JSON.stringify(String(q||"").trim())};
218
- const FOLLOWING = ${JSON.stringify(Boolean(b))};
217
+ const TARGET = ${JSON.stringify(String(e||"").trim())};
218
+ const FOLLOWING = ${JSON.stringify(Boolean(t))};
219
219
 
220
220
  async function resolveEntityUrn() {
221
221
  // 1. 原生 urn 直接用
@@ -1,8 +1,8 @@
1
- import{cli as L,Strategy as M}from"@jackwener/opencli/registry";import{AuthRequiredError as N,CommandExecutionError as H,EmptyResultError as O}from"@jackwener/opencli/errors";import{unwrapEvaluateResult as P}from"./shared.js";function Q(z){return`(async () => {
1
+ import{cli as c,Strategy as u}from"@jackwener/opencli/registry";import{AuthRequiredError as m,CommandExecutionError as r,EmptyResultError as l}from"@jackwener/opencli/errors";import{unwrapEvaluateResult as d}from"./shared.js";function p(t){return`(async () => {
2
2
  const norm = (s) => String(s == null ? '' : s).replace(/[ ]+/g, ' ').replace(/\\s+/g, ' ').trim();
3
3
  const csrf = ((document.cookie.split('; ').find((c) => c.startsWith('JSESSIONID=')) || '').split('=')[1] || '').replace(/^"|"$/g, '');
4
4
  if (!csrf) return { ok: false, auth: true };
5
- const res = await fetch('/voyager/api/voyagerFeedDashMainFeed?q=mainFeed&count=' + ${z}, { credentials: 'include', headers: {
5
+ const res = await fetch('/voyager/api/voyagerFeedDashMainFeed?q=mainFeed&count=' + ${t}, { credentials: 'include', headers: {
6
6
  'csrf-token': csrf,
7
7
  'accept': 'application/vnd.linkedin.normalized+json+2.1',
8
8
  'x-restli-protocol-version': '2.0.0',
@@ -34,4 +34,4 @@ import{cli as L,Strategy as M}from"@jackwener/opencli/registry";import{AuthRequi
34
34
  });
35
35
  }
36
36
  return { ok: true, posts };
37
- })()`}L({site:"linkedin",name:"timeline",access:"read",description:"Read LinkedIn home timeline posts via the Voyager feed API",domain:"www.linkedin.com",strategy:M.COOKIE,browser:!0,args:[{name:"limit",type:"int",default:20,help:"Number of posts to return (max 50)"}],columns:["rank","author","author_url","headline","text","posted_at","reactions","comments","url"],func:async(z,I)=>{if(!z)throw new H("Browser session required for linkedin timeline");const D=Math.max(1,Math.min(I.limit??20,50));await z.goto("https://www.linkedin.com/feed/");await z.wait(2);const B=P(await z.evaluate(Q(D)));if(B?.auth)throw new N("linkedin.com","LinkedIn timeline requires an active signed-in browser session");if(!B?.ok)throw new H(`LinkedIn timeline: feed API returned HTTP ${B?.status||"?"}`);const G=Array.isArray(B.posts)?B.posts:[];if(G.length===0)throw new O("linkedin timeline","The Voyager feed API returned no posts.");return G.slice(0,D).map((J,K)=>({rank:K+1,...J}))}});export const __test__={};
37
+ })()`}c({site:"linkedin",name:"timeline",access:"read",description:"Read LinkedIn home timeline posts via the Voyager feed API",domain:"www.linkedin.com",strategy:u.COOKIE,browser:!0,args:[{name:"limit",type:"int",default:20,help:"Number of posts to return (max 50)"}],columns:["rank","author","author_url","headline","text","posted_at","reactions","comments","url"],func:async(t,s)=>{if(!t)throw new r("Browser session required for linkedin timeline");const n=Math.max(1,Math.min(s.limit??20,50));await t.goto("https://www.linkedin.com/feed/");await t.wait(2);const e=d(await t.evaluate(p(n)));if(e?.auth)throw new m("linkedin.com","LinkedIn timeline requires an active signed-in browser session");if(!e?.ok)throw new r(`LinkedIn timeline: feed API returned HTTP ${e?.status||"?"}`);const o=Array.isArray(e.posts)?e.posts:[];if(o.length===0)throw new l("linkedin timeline","The Voyager feed API returned no posts.");return o.slice(0,n).map((i,a)=>({rank:a+1,...i}))}});export const __test__={};
@@ -1,4 +1,4 @@
1
- import{cli as E,Strategy as C}from"@jackwener/opencli/registry";import{ArgumentError as m,AuthRequiredError as g,CommandExecutionError as s,EmptyResultError as N}from"@jackwener/opencli/errors";const c="www.linkedin.com",l=50;function d(e){return String(e??"").replace(/[ ]/g," ").replace(/\s+/g," ").trim()}function h(e){if(e===void 0||e===null||e==="")return 10;const n=Number(e);if(!Number.isInteger(n)||n<1||n>l)throw new m(`--limit must be an integer between 1 and ${l}`);return n}function R(e){if(e&&typeof e==="object"&&"data"in e&&"session"in e)return e.data;return e}function p(e,n){return String.raw`(async () => {
1
+ import{cli as E,Strategy as N}from"@jackwener/opencli/registry";import{ArgumentError as m,AuthRequiredError as g,CommandExecutionError as s,EmptyResultError as A}from"@jackwener/opencli/errors";const c="www.linkedin.com",l=50;function d(e){return String(e??"").replace(/[ ]/g," ").replace(/\s+/g," ").trim()}function h(e){if(e===void 0||e===null||e==="")return 10;const n=Number(e);if(!Number.isInteger(n)||n<1||n>l)throw new m(`--limit must be an integer between 1 and ${l}`);return n}function C(e){if(e&&typeof e==="object"&&"data"in e&&"session"in e)return e.data;return e}function p(e,n){return String.raw`(async () => {
2
2
  try {
3
3
  const res = await fetch(${JSON.stringify(e)}, {
4
4
  credentials: 'include',
@@ -14,4 +14,4 @@ import{cli as E,Strategy as C}from"@jackwener/opencli/registry";import{ArgumentE
14
14
  } catch (e) {
15
15
  return { error: 'fetch failed: ' + ((e && e.message) || String(e)) };
16
16
  }
17
- })()`}function k(e){if(!Array.isArray(e))return"";return e.map((n)=>d((n?.firstName??"")+" "+(n?.lastName??""))).filter(Boolean).join(", ")}function y(e){const n=e?.["com.linkedin.common.TimeSpan"];if(!n||n.unit!=="SECOND")return"";return String(n.duration??"")}function S(e){if(!e)return"";if(typeof e.averageRating==="number")return e.averageRating.toFixed(2);if(typeof e.ratingSum==="number"&&typeof e.ratingCount==="number"&&e.ratingCount>0)return(e.ratingSum/e.ratingCount).toFixed(2);return""}function I(e,n){const r=e?.entityType||"",t=e?.slug||"";if(!t)return null;return{rank:n,type:r,title:e?.headline?.title?.text||"",instructor:k(e?.authors),difficulty:e?.difficultyLevel||"",duration_sec:y(e?.length),rating:S(e?.rating),rating_count:e?.rating?.ratingCount??"",viewers:e?.viewerCount??"",url:t?`https://www.linkedin.com/learning/${t}`:""}}E({site:"linkedin-learning",name:"search",access:"read",description:"Search LinkedIn Learning courses, videos, and learning paths by keyword",domain:c,strategy:C.COOKIE,browser:!0,args:[{name:"keywords",type:"string",required:!0,positional:!0,help:'Search keywords, e.g. "AI agent"'},{name:"limit",type:"int",default:10,help:`Maximum results to return (1-${l})`}],columns:["rank","type","title","instructor","difficulty","duration_sec","rating","rating_count","viewers","url"],func:async(e,n)=>{if(!e)throw new s("Browser session required for linkedin-learning search");const r=d(n.keywords);if(!r)throw new m("--keywords is required");const t=h(n.limit);await e.goto("https://www.linkedin.com/learning/");await e.wait(3);const w=(await e.getCookies({url:"https://www.linkedin.com"})).find((u)=>u.name==="JSESSIONID")?.value;if(!w)throw new g(c,"LinkedIn JSESSIONID cookie not found. Please sign in to LinkedIn in the browser.");const L=w.replace(/^"|"$/g,""),b=`https://www.linkedin.com/learning-api/searchV2?keywords=${encodeURIComponent(r)}&q=keywords`,i=R(await e.evaluate(p(b,L)));if(i?.authRequired)throw new g(c,`LinkedIn Learning auth failed (HTTP ${i.status??""}).`);if(!i?.json)throw new s(`LinkedIn Learning searchV2 failed: ${i?.error??"no payload"}`);const a=i.json?.elements;if(!Array.isArray(a))throw new s("LinkedIn Learning searchV2 returned malformed payload: missing elements array");if(a.length===0)throw new N(`No LinkedIn Learning results for "${r}"`);const o=[];for(const u of a){if(o.length>=t)break;const f=I(u,o.length+1);if(f)o.push(f)}if(o.length===0)throw new s("LinkedIn Learning searchV2 returned no parseable rows with slug identity");return o}});export const __test__={normalizeWhitespace:d,parseLimit:h,parseAuthors:k,durationSeconds:y,averageRating:S,parseRow:I,buildFetchScript:p};
17
+ })()`}function y(e){if(!Array.isArray(e))return"";return e.map((n)=>d((n?.firstName??"")+" "+(n?.lastName??""))).filter(Boolean).join(", ")}function k(e){const n=e?.["com.linkedin.common.TimeSpan"];if(!n||n.unit!=="SECOND")return"";return String(n.duration??"")}function S(e){if(!e)return"";if(typeof e.averageRating==="number")return e.averageRating.toFixed(2);if(typeof e.ratingSum==="number"&&typeof e.ratingCount==="number"&&e.ratingCount>0)return(e.ratingSum/e.ratingCount).toFixed(2);return""}function I(e,n){const r=e?.entityType||"",t=e?.slug||"";if(!t)return null;return{rank:n,type:r,title:e?.headline?.title?.text||"",instructor:y(e?.authors),difficulty:e?.difficultyLevel||"",duration_sec:k(e?.length),rating:S(e?.rating),rating_count:e?.rating?.ratingCount??"",viewers:e?.viewerCount??"",url:t?`https://www.linkedin.com/learning/${t}`:""}}E({site:"linkedin-learning",name:"search",access:"read",description:"Search LinkedIn Learning courses, videos, and learning paths by keyword",domain:c,strategy:N.COOKIE,browser:!0,args:[{name:"keywords",type:"string",required:!0,positional:!0,help:'Search keywords, e.g. "AI agent"'},{name:"limit",type:"int",default:10,help:`Maximum results to return (1-${l})`}],columns:["rank","type","title","instructor","difficulty","duration_sec","rating","rating_count","viewers","url"],func:async(e,n)=>{if(!e)throw new s("Browser session required for linkedin-learning search");const r=d(n.keywords);if(!r)throw new m("--keywords is required");const t=h(n.limit);await e.goto("https://www.linkedin.com/learning/");await e.wait(3);const f=(await e.getCookies({url:"https://www.linkedin.com"})).find((u)=>u.name==="JSESSIONID")?.value;if(!f)throw new g(c,"LinkedIn JSESSIONID cookie not found. Please sign in to LinkedIn in the browser.");const L=f.replace(/^"|"$/g,""),b=`https://www.linkedin.com/learning-api/searchV2?keywords=${encodeURIComponent(r)}&q=keywords`,i=C(await e.evaluate(p(b,L)));if(i?.authRequired)throw new g(c,`LinkedIn Learning auth failed (HTTP ${i.status??""}).`);if(!i?.json)throw new s(`LinkedIn Learning searchV2 failed: ${i?.error??"no payload"}`);const a=i.json?.elements;if(!Array.isArray(a))throw new s("LinkedIn Learning searchV2 returned malformed payload: missing elements array");if(a.length===0)throw new A(`No LinkedIn Learning results for "${r}"`);const o=[];for(const u of a){if(o.length>=t)break;const w=I(u,o.length+1);if(w)o.push(w)}if(o.length===0)throw new s("LinkedIn Learning searchV2 returned no parseable rows with slug identity");return o}});export const __test__={normalizeWhitespace:d,parseLimit:h,parseAuthors:y,durationSeconds:k,averageRating:S,parseRow:I,buildFetchScript:p};
@@ -1,4 +1,4 @@
1
- import{cli as R,Strategy as $}from"@jackwener/opencli/registry";import{ArgumentError as x,AuthRequiredError as y,CommandExecutionError as a,EmptyResultError as C}from"@jackwener/opencli/errors";const c="www.linkedin.com",d=50,N=25;function L(e){if(e===void 0||e===null||e==="")return 10;const n=Number(e);if(!Number.isInteger(n)||n<1||n>d)throw new x(`--limit must be an integer between 1 and ${d}`);return n}function O(e){if(e&&typeof e==="object"&&"data"in e&&"session"in e)return e.data;return e}function T(e,n){return String.raw`(async () => {
1
+ import{cli as R,Strategy as x}from"@jackwener/opencli/registry";import{ArgumentError as C,AuthRequiredError as y,CommandExecutionError as a,EmptyResultError as N}from"@jackwener/opencli/errors";const c="www.linkedin.com",d=50,O=25;function L(e){if(e===void 0||e===null||e==="")return 10;const n=Number(e);if(!Number.isInteger(n)||n<1||n>d)throw new C(`--limit must be an integer between 1 and ${d}`);return n}function j(e){if(e&&typeof e==="object"&&"data"in e&&"session"in e)return e.data;return e}function _(e,n){return String.raw`(async () => {
2
2
  try {
3
3
  const res = await fetch(${JSON.stringify(e)}, {
4
4
  credentials: 'include',
@@ -14,4 +14,4 @@ import{cli as R,Strategy as $}from"@jackwener/opencli/registry";import{ArgumentE
14
14
  } catch (e) {
15
15
  return { error: 'fetch failed: ' + ((e && e.message) || String(e)) };
16
16
  }
17
- })()`}function I(e,n,r){const s=e?.slug||"";if(!s)return null;return{rank:r,group:n?.title?.text||n?.annotation||"",type:e?.entityType||e?.localizedEntityName||"",title:e?.title?.text||e?.headline?.title?.text||e?.headline?.text||"",difficulty:e?.difficultyLevel||"",viewers:e?.viewerCount??"",url:s?`https://www.linkedin.com/learning/${s}`:""}}R({site:"linkedin-learning",name:"trending",access:"read",description:"Browse LinkedIn Learning recommended courses across personalized carousels",domain:c,strategy:$.COOKIE,browser:!0,args:[{name:"limit",type:"int",default:10,help:`Maximum results to return (1-${d})`}],columns:["rank","group","type","title","difficulty","viewers","url"],func:async(e,n)=>{if(!e)throw new a("Browser session required for linkedin-learning trending");const r=L(n.limit);await e.goto("https://www.linkedin.com/learning/");await e.wait(3);const f=(await e.getCookies({url:"https://www.linkedin.com"})).find((o)=>o.name==="JSESSIONID")?.value;if(!f)throw new y(c,"LinkedIn JSESSIONID cookie not found. Please sign in to LinkedIn in the browser.");const S=f.replace(/^"|"$/g,""),E=`https://www.linkedin.com/learning-api/feedRecommendationGroups?countPerCarousel=${N}&q=learner`,i=O(await e.evaluate(T(E,S)));if(i?.authRequired)throw new y(c,`LinkedIn Learning auth failed (HTTP ${i.status??""}).`);if(!i?.json)throw new a(`LinkedIn Learning feedRecommendationGroups failed: ${i?.error??"no payload"}`);const m=i.json?.elements;if(!Array.isArray(m))throw new a("LinkedIn Learning feedRecommendationGroups returned malformed payload: missing elements array");const t=[],w=new Set;let g=1,h=!1;for(const o of m){const b=Array.isArray(o?.carousels)?o.carousels:[];for(const u of b){const A=Array.isArray(u?.cards)?u.cards:[];for(const p of A){h=!0;if(t.length>=r)break;const l=p?.slug;if(!l||w.has(l))continue;w.add(l);const k=I(p,u,g);if(!k)continue;t.push(k);g+=1}if(t.length>=r)break}if(t.length>=r)break}if(t.length===0){if(h)throw new a("LinkedIn Learning feedRecommendationGroups returned no parseable cards with slug identity");throw new C("LinkedIn Learning returned no personalized recommendations")}return t}});export const __test__={parseLimit:L,parseCard:I};
17
+ })()`}function I(e,n,r){const s=e?.slug||"";if(!s)return null;return{rank:r,group:n?.title?.text||n?.annotation||"",type:e?.entityType||e?.localizedEntityName||"",title:e?.title?.text||e?.headline?.title?.text||e?.headline?.text||"",difficulty:e?.difficultyLevel||"",viewers:e?.viewerCount??"",url:s?`https://www.linkedin.com/learning/${s}`:""}}R({site:"linkedin-learning",name:"trending",access:"read",description:"Browse LinkedIn Learning recommended courses across personalized carousels",domain:c,strategy:x.COOKIE,browser:!0,args:[{name:"limit",type:"int",default:10,help:`Maximum results to return (1-${d})`}],columns:["rank","group","type","title","difficulty","viewers","url"],func:async(e,n)=>{if(!e)throw new a("Browser session required for linkedin-learning trending");const r=L(n.limit);await e.goto("https://www.linkedin.com/learning/");await e.wait(3);const f=(await e.getCookies({url:"https://www.linkedin.com"})).find((o)=>o.name==="JSESSIONID")?.value;if(!f)throw new y(c,"LinkedIn JSESSIONID cookie not found. Please sign in to LinkedIn in the browser.");const S=f.replace(/^"|"$/g,""),E=`https://www.linkedin.com/learning-api/feedRecommendationGroups?countPerCarousel=${O}&q=learner`,i=j(await e.evaluate(_(E,S)));if(i?.authRequired)throw new y(c,`LinkedIn Learning auth failed (HTTP ${i.status??""}).`);if(!i?.json)throw new a(`LinkedIn Learning feedRecommendationGroups failed: ${i?.error??"no payload"}`);const w=i.json?.elements;if(!Array.isArray(w))throw new a("LinkedIn Learning feedRecommendationGroups returned malformed payload: missing elements array");const t=[],m=new Set;let g=1,h=!1;for(const o of w){const b=Array.isArray(o?.carousels)?o.carousels:[];for(const u of b){const A=Array.isArray(u?.cards)?u.cards:[];for(const p of A){h=!0;if(t.length>=r)break;const l=p?.slug;if(!l||m.has(l))continue;m.add(l);const k=I(p,u,g);if(!k)continue;t.push(k);g+=1}if(t.length>=r)break}if(t.length>=r)break}if(t.length===0){if(h)throw new a("LinkedIn Learning feedRecommendationGroups returned no parseable cards with slug identity");throw new N("LinkedIn Learning returned no personalized recommendations")}return t}});export const __test__={parseLimit:L,parseCard:I};