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 +1 @@
1
- import{cli as N,Strategy as A}from"@jackwener/opencli/registry";import{ArgumentError as U,AuthRequiredError as K,CommandExecutionError as S,EmptyResultError as w}from"@jackwener/opencli/errors";const D="linkedin.com",f="https://www.linkedin.com/messaging/",T=1,x=100,_=40;function R(H){if(H&&typeof H==="object"&&"data"in H&&"session"in H)return H.data;return H}function b(H){return H?`https://www.linkedin.com/messaging/thread/${H}/`:""}function z(){if(/\/(login|checkpoint|authwall|uas)/i.test(location.pathname))return{loginRequired:!0};const H=performance.getEntriesByType("resource").map((P)=>P.name),Z=(P)=>H.find((G)=>/messengerConversations\.[a-f0-9]+/i.test(G)&&P.test(G)),J=Z(/PRIMARY_INBOX/i)||Z(/conversationCategoryPredicate/i)||H.find((P)=>/messengerConversations\.[a-f0-9]+/i.test(P)&&/mailboxUrn/i.test(P));if(!J)return{url:null};const W=J.match(/mailboxUrn:(urn[^,)&]+)/i);return{url:J,mailboxUrn:W?decodeURIComponent(W[1]):""}}async function E(H,Z){try{const J=await fetch(H,{credentials:"include",headers:{"csrf-token":Z,accept:"application/vnd.linkedin.normalized+json+2.1","x-restli-protocol-version":"2.0.0"}});if(J.status===401||J.status===403)return{authRequired:!0,error:"HTTP "+J.status};if(!J.ok)return{error:"HTTP "+J.status};return{json:await J.json()}}catch(J){return{error:"fetch failed: "+(J&&J.message||String(J))}}}function k(H,Z){if(!H||typeof H!=="object"||Array.isArray(H)||!Array.isArray(H.included))throw new S("LinkedIn messaging API returned malformed normalized payload: missing included array");const J=H.included,W=new Map;for(const B of J)if(B&&B.entityUrn)W.set(B.entityUrn,B);const P=(B)=>String(B==null?"":B).replace(/\s+/g," ").trim(),G=(B)=>{if(!B)return{name:"",kind:""};const Q=B.participantType||{};if(Q.organization&&Q.organization.name)return{name:P(Q.organization.name.text),kind:"organization"};if(Q.member){const V=Q.member.firstName&&Q.member.firstName.text,$=Q.member.lastName&&Q.member.lastName.text;return{name:P([V,$].filter(Boolean).join(" ")),kind:"member"}}if(Q.agent&&Q.agent.name)return{name:P(Q.agent.name.text),kind:"agent"};return{name:"",kind:""}},F=[];for(const B of J){if(!B||B.$type!=="com.linkedin.messenger.Conversation")continue;const Q=String(B.backendUrn||"").replace(/^urn:li:messagingThread:/,"");if(!Q)throw new S("LinkedIn messaging API returned a conversation without thread id");const V=[];let $="";for(const L of B["*conversationParticipants"]||[]){const O=W.get(L);if(!O)continue;if(Z&&O.hostIdentityUrn===Z)continue;const C=G(O);if(C.name){V.push(C.name);if(!$)$=C.kind}}const Y=B.messages&&B.messages["*elements"]||[],X=W.get(Y[0]);let j=X&&X.body?P(X.body.text):"";if(!j)j=P(B.descriptionText||"");const q=Number(B.lastActivityAt||0);F.push({activityMs:q,row:{thread_id:Q,person_name:B.title?P(B.title):V.join(", "),last_message_preview:j.slice(0,300),unread:Number(B.unreadCount||0)>0||B.read===!1,counterparty_type:$,category:Array.isArray(B.categories)?B.categories.join(","):"",timestamp:q?new Date(q).toISOString():""}})}F.sort((B,Q)=>Q.activityMs-B.activityMs);return F.map((B)=>B.row)}N({site:"linkedin",name:"inbox",access:"read",description:"List LinkedIn messaging inbox conversations and unread messages",domain:"www.linkedin.com",strategy:A.COOKIE,browser:!0,args:[{name:"limit",type:"int",default:_,help:"Maximum conversations to return (1-100)"},{name:"unread-only",type:"bool",default:!1,help:"Return only conversations with unread messages"}],columns:["rank","thread_url","thread_id","person_name","last_message_preview","unread","counterparty_type","category","timestamp"],func:async(H,Z)=>{let J=_;if(Z.limit!==void 0&&Z.limit!==null&&Z.limit!==""){J=Number(Z.limit);if(!Number.isInteger(J)||J<T||J>x)throw new U(`--limit must be an integer between ${T} and ${x}`)}const W=Boolean(Z["unread-only"]);await H.goto(f);await H.wait(10);let P=R(await H.evaluate(`(${z.toString()})()`));if(P&&P.loginRequired)throw new K(D,"LinkedIn requires an active signed-in browser session.");if(!P||!P.url){await H.wait(6);P=R(await H.evaluate(`(${z.toString()})()`))}if(!P||!P.url)throw new S("LinkedIn did not issue a messaging API request; the inbox may have failed to load.");const F=(await H.getCookies({url:"https://www.linkedin.com"})).find((Y)=>Y.name==="JSESSIONID")?.value;if(!F)throw new K(D,"LinkedIn JSESSIONID cookie not found. Please sign in to LinkedIn.");const B=F.replace(/^"|"$/g,""),Q=P.url.replace(/count:\d+/,"count:"+J),V=R(await H.evaluate(`(${E.toString()})(${JSON.stringify(Q)}, ${JSON.stringify(B)})`));if(V&&V.authRequired)throw new K(D,"LinkedIn messaging API authentication failed: "+V.error);if(!V||V.error||!V.json)throw new S("LinkedIn messaging API returned an unexpected response: "+(V&&V.error||"no data"));let $=k(V.json,P.mailboxUrn||"");if(W)$=$.filter((Y)=>Y.unread);if($.length===0){if(W)return[];throw new w("linkedin inbox","No LinkedIn conversations were found in the inbox.")}return $.slice(0,J).map((Y,X)=>({rank:X+1,thread_url:b(Y.thread_id),thread_id:Y.thread_id,person_name:Y.person_name,last_message_preview:Y.last_message_preview,unread:Y.unread,counterparty_type:Y.counterparty_type,category:Y.category,timestamp:Y.timestamp}))}});export const __test__={parseConversations:k,threadUrl:b};
1
+ import{cli as L,Strategy as M}from"@jackwener/opencli/registry";import{ArgumentError as U,AuthRequiredError as y,CommandExecutionError as f,EmptyResultError as E}from"@jackwener/opencli/errors";const I="linkedin.com",R="https://www.linkedin.com/messaging/",k=1,v=100,b=40;function _(n){if(n&&typeof n==="object"&&"data"in n&&"session"in n)return n.data;return n}function A(n){return n?`https://www.linkedin.com/messaging/thread/${n}/`:""}function x(){if(/\/(login|checkpoint|authwall|uas)/i.test(location.pathname))return{loginRequired:!0};const n=performance.getEntriesByType("resource").map((r)=>r.name),s=(r)=>n.find((d)=>/messengerConversations\.[a-f0-9]+/i.test(d)&&r.test(d)),t=s(/PRIMARY_INBOX/i)||s(/conversationCategoryPredicate/i)||n.find((r)=>/messengerConversations\.[a-f0-9]+/i.test(r)&&/mailboxUrn/i.test(r));if(!t)return{url:null};const u=t.match(/mailboxUrn:(urn[^,)&]+)/i);return{url:t,mailboxUrn:u?decodeURIComponent(u[1]):""}}async function T(n,s){try{const t=await fetch(n,{credentials:"include",headers:{"csrf-token":s,accept:"application/vnd.linkedin.normalized+json+2.1","x-restli-protocol-version":"2.0.0"}});if(t.status===401||t.status===403)return{authRequired:!0,error:"HTTP "+t.status};if(!t.ok)return{error:"HTTP "+t.status};return{json:await t.json()}}catch(t){return{error:"fetch failed: "+(t&&t.message||String(t))}}}function N(n,s){if(!n||typeof n!=="object"||Array.isArray(n)||!Array.isArray(n.included))throw new f("LinkedIn messaging API returned malformed normalized payload: missing included array");const t=n.included,u=new Map;for(const e of t)if(e&&e.entityUrn)u.set(e.entityUrn,e);const r=(e)=>String(e==null?"":e).replace(/\s+/g," ").trim(),d=(e)=>{if(!e)return{name:"",kind:""};const i=e.participantType||{};if(i.organization&&i.organization.name)return{name:r(i.organization.name.text),kind:"organization"};if(i.member){const a=i.member.firstName&&i.member.firstName.text,c=i.member.lastName&&i.member.lastName.text;return{name:r([a,c].filter(Boolean).join(" ")),kind:"member"}}if(i.agent&&i.agent.name)return{name:r(i.agent.name.text),kind:"agent"};return{name:"",kind:""}},m=[];for(const e of t){if(!e||e.$type!=="com.linkedin.messenger.Conversation")continue;const i=String(e.backendUrn||"").replace(/^urn:li:messagingThread:/,"");if(!i)throw new f("LinkedIn messaging API returned a conversation without thread id");const a=[];let c="";for(const S of e["*conversationParticipants"]||[]){const w=u.get(S);if(!w)continue;if(s&&w.hostIdentityUrn===s)continue;const h=d(w);if(h.name){a.push(h.name);if(!c)c=h.kind}}const o=e.messages&&e.messages["*elements"]||[],l=u.get(o[0]);let g=l&&l.body?r(l.body.text):"";if(!g)g=r(e.descriptionText||"");const p=Number(e.lastActivityAt||0);m.push({activityMs:p,row:{thread_id:i,person_name:e.title?r(e.title):a.join(", "),last_message_preview:g.slice(0,300),unread:Number(e.unreadCount||0)>0||e.read===!1,counterparty_type:c,category:Array.isArray(e.categories)?e.categories.join(","):"",timestamp:p?new Date(p).toISOString():""}})}m.sort((e,i)=>i.activityMs-e.activityMs);return m.map((e)=>e.row)}L({site:"linkedin",name:"inbox",access:"read",description:"List LinkedIn messaging inbox conversations and unread messages",domain:"www.linkedin.com",strategy:M.COOKIE,browser:!0,args:[{name:"limit",type:"int",default:b,help:"Maximum conversations to return (1-100)"},{name:"unread-only",type:"bool",default:!1,help:"Return only conversations with unread messages"}],columns:["rank","thread_url","thread_id","person_name","last_message_preview","unread","counterparty_type","category","timestamp"],func:async(n,s)=>{let t=b;if(s.limit!==void 0&&s.limit!==null&&s.limit!==""){t=Number(s.limit);if(!Number.isInteger(t)||t<k||t>v)throw new U(`--limit must be an integer between ${k} and ${v}`)}const u=Boolean(s["unread-only"]);await n.goto(R);await n.wait(10);let r=_(await n.evaluate(`(${x.toString()})()`));if(r&&r.loginRequired)throw new y(I,"LinkedIn requires an active signed-in browser session.");if(!r||!r.url){await n.wait(6);r=_(await n.evaluate(`(${x.toString()})()`))}if(!r||!r.url)throw new f("LinkedIn did not issue a messaging API request; the inbox may have failed to load.");const m=(await n.getCookies({url:"https://www.linkedin.com"})).find((o)=>o.name==="JSESSIONID")?.value;if(!m)throw new y(I,"LinkedIn JSESSIONID cookie not found. Please sign in to LinkedIn.");const e=m.replace(/^"|"$/g,""),i=r.url.replace(/count:\d+/,"count:"+t),a=_(await n.evaluate(`(${T.toString()})(${JSON.stringify(i)}, ${JSON.stringify(e)})`));if(a&&a.authRequired)throw new y(I,"LinkedIn messaging API authentication failed: "+a.error);if(!a||a.error||!a.json)throw new f("LinkedIn messaging API returned an unexpected response: "+(a&&a.error||"no data"));let c=N(a.json,r.mailboxUrn||"");if(u)c=c.filter((o)=>o.unread);if(c.length===0){if(u)return[];throw new E("linkedin inbox","No LinkedIn conversations were found in the inbox.")}return c.slice(0,t).map((o,l)=>({rank:l+1,thread_url:A(o.thread_id),thread_id:o.thread_id,person_name:o.person_name,last_message_preview:o.last_message_preview,unread:o.unread,counterparty_type:o.counterparty_type,category:o.category,timestamp:o.timestamp}))}});export const __test__={parseConversations:N,threadUrl:A};
@@ -1,8 +1,8 @@
1
- import{cli as V,Strategy as X}from"@jackwener/opencli/registry";import{AuthRequiredError as Y,ArgumentError as Z,CommandExecutionError as P,EmptyResultError as $}from"@jackwener/opencli/errors";import{assertSafeLinkedinUrl as f,normalizeWhitespace as G,unwrapEvaluateResult as q}from"./shared.js";const B="com.linkedin.voyager.deco.jobs.web.shared.WebFullJobPosting-65";function Q(H){const M=f(H,"job-url"),K=new URL(M),F=K.pathname.match(/^\/jobs\/view\/(?:[^/]+-)?(\d+)/)||K.search.match(/[?&]currentJobId=(\d+)/);if(!F)throw new Z("job-url must be a https://www.linkedin.com/jobs/view/<id> URL");return F[1]}function D(H,M){return`(async () => {
1
+ import{cli as l,Strategy as p}from"@jackwener/opencli/registry";import{AuthRequiredError as c,ArgumentError as d,CommandExecutionError as a,EmptyResultError as u}from"@jackwener/opencli/errors";import{assertSafeLinkedinUrl as m,normalizeWhitespace as t,unwrapEvaluateResult as y}from"./shared.js";const w="com.linkedin.voyager.deco.jobs.web.shared.WebFullJobPosting-65";function i(o){const r=m(o,"job-url"),n=new URL(r),e=n.pathname.match(/^\/jobs\/view\/(?:[^/]+-)?(\d+)/)||n.search.match(/[?&]currentJobId=(\d+)/);if(!e)throw new d("job-url must be a https://www.linkedin.com/jobs/view/<id> URL");return e[1]}function b(o,r){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/jobs/jobPostings/' + ${JSON.stringify(H)} + '?decorationId=' + ${JSON.stringify(M)}, { credentials: 'include', headers: {
5
+ const res = await fetch('/voyager/api/jobs/jobPostings/' + ${JSON.stringify(o)} + '?decorationId=' + ${JSON.stringify(r)}, { 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',
@@ -37,4 +37,4 @@ import{cli as V,Strategy as X}from"@jackwener/opencli/registry";import{AuthRequi
37
37
  apply_url: applyUrl,
38
38
  description: textOf(d.description),
39
39
  };
40
- })()`}V({site:"linkedin",name:"job-detail",access:"read",description:"Read one LinkedIn job via the Voyager API: description, apply URL, workplace type, applicants, and company metadata",domain:"www.linkedin.com",strategy:X.COOKIE,browser:!0,args:[{name:"job-url",type:"string",required:!0,positional:!0,help:"Exact LinkedIn job URL, e.g. https://www.linkedin.com/jobs/view/123/"}],columns:["title","company","location","workplace_type","job_type","applicants","listed","apply_url","company_url","url","description"],func:async(H,M)=>{if(!H)throw new P("Browser session required for linkedin job-detail");const K=Q(M["job-url"]);await H.goto("https://www.linkedin.com/jobs/");await H.wait(2);const F=q(await H.evaluate(D(K,B)));if(F?.auth)throw new Y("linkedin.com","LinkedIn job-detail requires an active signed-in browser session");if(!F?.ok)throw new P(`LinkedIn job-detail: jobPostings API returned HTTP ${F?.status||"?"}`);if(!G(F.title))throw new $("linkedin job-detail",`No job posting found for id ${K} (it may be closed or removed).`);const T=F.listed_at?new Date(F.listed_at).toISOString().slice(0,10):"";return[{title:G(F.title),company:G(F.company),location:G(F.location),workplace_type:G(F.workplace_type),job_type:G(F.job_type),applicants:F.applicants||0,listed:T,apply_url:G(F.apply_url),company_url:G(F.company_url),url:`https://www.linkedin.com/jobs/view/${K}`,description:G(F.description)}]}});export const __test__={extractJobId:Q};
40
+ })()`}l({site:"linkedin",name:"job-detail",access:"read",description:"Read one LinkedIn job via the Voyager API: description, apply URL, workplace type, applicants, and company metadata",domain:"www.linkedin.com",strategy:p.COOKIE,browser:!0,args:[{name:"job-url",type:"string",required:!0,positional:!0,help:"Exact LinkedIn job URL, e.g. https://www.linkedin.com/jobs/view/123/"}],columns:["title","company","location","workplace_type","job_type","applicants","listed","apply_url","company_url","url","description"],func:async(o,r)=>{if(!o)throw new a("Browser session required for linkedin job-detail");const n=i(r["job-url"]);await o.goto("https://www.linkedin.com/jobs/");await o.wait(2);const e=y(await o.evaluate(b(n,w)));if(e?.auth)throw new c("linkedin.com","LinkedIn job-detail requires an active signed-in browser session");if(!e?.ok)throw new a(`LinkedIn job-detail: jobPostings API returned HTTP ${e?.status||"?"}`);if(!t(e.title))throw new u("linkedin job-detail",`No job posting found for id ${n} (it may be closed or removed).`);const s=e.listed_at?new Date(e.listed_at).toISOString().slice(0,10):"";return[{title:t(e.title),company:t(e.company),location:t(e.location),workplace_type:t(e.workplace_type),job_type:t(e.job_type),applicants:e.applicants||0,listed:s,apply_url:t(e.apply_url),company_url:t(e.company_url),url:`https://www.linkedin.com/jobs/view/${n}`,description:t(e.description)}]}});export const __test__={extractJobId:i};
@@ -1 +1 @@
1
- import{cli as Z,Strategy as $}from"@jackwener/opencli/registry";import{AuthRequiredError as q,CommandExecutionError as W}from"@jackwener/opencli/errors";import{LINKEDIN_DOMAIN as X,unwrapEvaluateResult as G}from"./shared.js";import{buildCommentReactScript as b,buildReactScript as x,looksLikeCommentUrn as z,normalizeCommentUrn as K,normalizeThreadUrn as M,parseReactionType as w,REACTION_CREATE_QID as Q,REACTION_DELETE_QID as h}from"./social-api.js";Z({site:"linkedin",name:"like",access:"write",description:"React to a LinkedIn post OR comment (like by default; also celebrate/support/love/insightful/funny), or remove your reaction. Takes a post URL / activity urn, or a comment_urn from `linkedin post-comments`.",domain:X,strategy:$.COOKIE,browser:!0,args:[{name:"target",type:"string",required:!0,positional:!0,help:"What to react to: a LinkedIn post URL (…/feed/update/…) or activity/ugcPost urn, OR a comment_urn (urn:li:comment:(…)) from `linkedin post-comments`."},{name:"reaction",type:"string",required:!1,default:"like",help:"Reaction type: like (default), celebrate, support, love, insightful, funny. Ignored when --remove true."},{name:"remove",type:"bool",required:!1,default:!1,help:"Remove your existing reaction instead of adding one."}],columns:["status","target_urn","target_type","reaction"],func:async(H,B)=>{if(!H)throw new W("Browser session required for linkedin like");const F=B?.remove===!0||B?.remove==="true",J=F?"":w(B?.reaction),P=z(B?.target),V=P?K(B?.target):M(B?.target);await H.goto("https://www.linkedin.com/feed/");await H.wait(2);const Y=P?b({commentUrn:V,reactionType:J,remove:F,createQid:Q,deleteQid:h}):x({threadUrn:V,reactionType:J,remove:F}),f=G(await H.evaluate(Y));if(!f?.ok){if(f?.stage==="auth"||f?.httpStatus===401||f?.httpStatus===403)throw new q(X,`LinkedIn like requires an active signed-in LinkedIn browser session (${f?.error||"auth"}).`);throw new W(`LinkedIn like failed: stage=${f?.stage||"unknown"} http=${f?.httpStatus||"?"} ${f?.error||""}`.trim())}return[{status:F?"reaction_removed":"reacted",target_urn:V,target_type:P?"comment":"post",reaction:F?"":J}]}});
1
+ import{cli as c,Strategy as l}from"@jackwener/opencli/registry";import{AuthRequiredError as d,CommandExecutionError as s}from"@jackwener/opencli/errors";import{LINKEDIN_DOMAIN as m,unwrapEvaluateResult as p}from"./shared.js";import{buildCommentReactScript as f,buildReactScript as k,looksLikeCommentUrn as h,normalizeCommentUrn as w,normalizeThreadUrn as y,parseReactionType as g,REACTION_CREATE_QID as v,REACTION_DELETE_QID as R}from"./social-api.js";c({site:"linkedin",name:"like",access:"write",description:"React to a LinkedIn post OR comment (like by default; also celebrate/support/love/insightful/funny), or remove your reaction. Takes a post URL / activity urn, or a comment_urn from `linkedin post-comments`.",domain:m,strategy:l.COOKIE,browser:!0,args:[{name:"target",type:"string",required:!0,positional:!0,help:"What to react to: a LinkedIn post URL (…/feed/update/…) or activity/ugcPost urn, OR a comment_urn (urn:li:comment:(…)) from `linkedin post-comments`."},{name:"reaction",type:"string",required:!1,default:"like",help:"Reaction type: like (default), celebrate, support, love, insightful, funny. Ignored when --remove true."},{name:"remove",type:"bool",required:!1,default:!1,help:"Remove your existing reaction instead of adding one."}],columns:["status","target_urn","target_type","reaction"],func:async(n,t)=>{if(!n)throw new s("Browser session required for linkedin like");const r=t?.remove===!0||t?.remove==="true",o=r?"":g(t?.reaction),i=h(t?.target),a=i?w(t?.target):y(t?.target);await n.goto("https://www.linkedin.com/feed/");await n.wait(2);const u=i?f({commentUrn:a,reactionType:o,remove:r,createQid:v,deleteQid:R}):k({threadUrn:a,reactionType:o,remove:r}),e=p(await n.evaluate(u));if(!e?.ok){if(e?.stage==="auth"||e?.httpStatus===401||e?.httpStatus===403)throw new d(m,`LinkedIn like requires an active signed-in LinkedIn browser session (${e?.error||"auth"}).`);throw new s(`LinkedIn like failed: stage=${e?.stage||"unknown"} http=${e?.httpStatus||"?"} ${e?.error||""}`.trim())}return[{status:r?"reaction_removed":"reacted",target_urn:a,target_type:i?"comment":"post",reaction:r?"":o}]}});
@@ -1 +1 @@
1
- import{cli as X,Strategy as Z}from"@jackwener/opencli/registry";import{ArgumentError as b,AuthRequiredError as f,CommandExecutionError as G,EmptyResultError as j}from"@jackwener/opencli/errors";import{LINKEDIN_DOMAIN as K,normalizeWhitespace as C,parseLimit as x,unwrapEvaluateResult as z}from"./shared.js";import{buildNotificationsScript as O}from"./social-api.js";const P=20,U=100,k=20,R={all:"all",mentions:"mentions",posts:"my_posts_all",jobs:"job_alerts"};X({site:"linkedin",name:"notifications",access:"read",description:"Read your LinkedIn notifications via the Voyager API: who reacted to / commented on / mentioned your posts, profile views, follows, and more. Read-only.",domain:K,strategy:Z.COOKIE,browser:!0,args:[{name:"limit",type:"int",required:!1,default:P,help:`Maximum notifications to return (1-${U}).`},{name:"filter",type:"string",required:!1,default:"all",help:"Which notifications: all (default), mentions, posts (activity on your posts), jobs."},{name:"unread-only",type:"bool",required:!1,default:!1,help:"Only return unread notifications."}],columns:["rank","unread","headline","content","when","target"],func:async(Q,H)=>{if(!Q)throw new G("Browser session required for linkedin notifications");const V=x(H?.limit,P,U),W=String(H?.filter??"all").trim().toLowerCase(),v=R[W];if(!v)throw new b(`--filter 只能是 all / mentions / posts / jobs(收到 "${H?.filter}")`);const F=H?.["unread-only"]===!0||H?.["unread-only"]==="true";await Q.goto("https://www.linkedin.com/feed/");await Q.wait(2);const $=[];for(let Y=0;$.length<V&&Y<U;Y+=k){const B=z(await Q.evaluate(O({count:k,start:Y,filter:v})));if(!B?.ok){if(B?.stage==="auth"||B?.httpStatus===401||B?.httpStatus===403)throw new f(K,`LinkedIn notifications requires an active signed-in LinkedIn browser session (${B?.error||"auth"}).`);throw new G(`LinkedIn notifications failed: stage=${B?.stage||"read"} http=${B?.httpStatus||"?"} ${B?.error||""}`.trim())}const q=Array.isArray(B.rows)?B.rows:[];if(q.length===0)break;for(const J of q){if(F&&J.read)continue;$.push({unread:J.read?"":"yes",headline:C(J.headline),content:C(J.content),when:J.when?new Date(J.when).toISOString():"",target:y(J.target)})}if(q.length<k)break}if($.length===0)throw new j("linkedin notifications",F?"No unread notifications.":"No notifications were returned for this filter.");return $.slice(0,V).map((Y,B)=>({rank:B+1,...Y}))}});function y(Q){const H=C(Q);if(!H)return"";try{const V=new URL(H,"https://www.linkedin.com");if(V.protocol!=="https:")return"";return V.toString()}catch{return""}}
1
+ import{cli as y,Strategy as I}from"@jackwener/opencli/registry";import{ArgumentError as g,AuthRequiredError as k,CommandExecutionError as m,EmptyResultError as E}from"@jackwener/opencli/errors";import{LINKEDIN_DOMAIN as w,normalizeWhitespace as l,parseLimit as L,unwrapEvaluateResult as b}from"./shared.js";import{buildNotificationsScript as S}from"./social-api.js";const h=20,c=100,u=20,A={all:"all",mentions:"mentions",posts:"my_posts_all",jobs:"job_alerts"};y({site:"linkedin",name:"notifications",access:"read",description:"Read your LinkedIn notifications via the Voyager API: who reacted to / commented on / mentioned your posts, profile views, follows, and more. Read-only.",domain:w,strategy:I.COOKIE,browser:!0,args:[{name:"limit",type:"int",required:!1,default:h,help:`Maximum notifications to return (1-${c}).`},{name:"filter",type:"string",required:!1,default:"all",help:"Which notifications: all (default), mentions, posts (activity on your posts), jobs."},{name:"unread-only",type:"bool",required:!1,default:!1,help:"Only return unread notifications."}],columns:["rank","unread","headline","content","when","target"],func:async(i,e)=>{if(!i)throw new m("Browser session required for linkedin notifications");const r=L(e?.limit,h,c),p=String(e?.filter??"all").trim().toLowerCase(),f=A[p];if(!f)throw new g(`--filter 只能是 all / mentions / posts / jobs(收到 "${e?.filter}")`);const d=e?.["unread-only"]===!0||e?.["unread-only"]==="true";await i.goto("https://www.linkedin.com/feed/");await i.wait(2);const a=[];for(let o=0;a.length<r&&o<c;o+=u){const t=b(await i.evaluate(S({count:u,start:o,filter:f})));if(!t?.ok){if(t?.stage==="auth"||t?.httpStatus===401||t?.httpStatus===403)throw new k(w,`LinkedIn notifications requires an active signed-in LinkedIn browser session (${t?.error||"auth"}).`);throw new m(`LinkedIn notifications failed: stage=${t?.stage||"read"} http=${t?.httpStatus||"?"} ${t?.error||""}`.trim())}const s=Array.isArray(t.rows)?t.rows:[];if(s.length===0)break;for(const n of s){if(d&&n.read)continue;a.push({unread:n.read?"":"yes",headline:l(n.headline),content:l(n.content),when:n.when?new Date(n.when).toISOString():"",target:R(n.target)})}if(s.length<u)break}if(a.length===0)throw new E("linkedin notifications",d?"No unread notifications.":"No notifications were returned for this filter.");return a.slice(0,r).map((o,t)=>({rank:t+1,...o}))}});function R(i){const e=l(i);if(!e)return"";try{const r=new URL(e,"https://www.linkedin.com");if(r.protocol!=="https:")return"";return r.toString()}catch{return""}}
@@ -1 +1 @@
1
- import{cli as z,Strategy as C}from"@jackwener/opencli/registry";import{ArgumentError as $,CommandExecutionError as M,EmptyResultError as P}from"@jackwener/opencli/errors";import{fetchSearchClusters as W}from"./search-api.js";const N="www.linkedin.com",R=10;function F(B){return String(B??"").replace(/[ ]/g," ").replace(/\s+/g," ").trim()}function _(B,G,H=G){const J=F(B[G]);if(!J)throw new $(`${H} is required`);return J}function S(B){if(B===void 0||B===null||B==="")return 5;const G=Number(B);if(!Number.isInteger(G)||G<1||G>R)throw new $(`--limit must be an integer between 1 and ${R}`);return G}const f={"1":"F","2":"S","3":"O"},O=new Set(["proBono","boardMember"]);function K(B){if(!B)return[];return String(B).split(",").map((G)=>G.trim()).filter(Boolean)}function X(B){if(!B)return[];const G=K(B),H=[];for(const J of G){const Q=f[J];if(!Q)throw new $(`--network values must be one or more of 1,2,3 (got "${J}")`);if(!H.includes(Q))H.push(Q)}return H}function D(B){if(!B)return[];const G=K(B).map((H)=>H.toLowerCase());for(const H of G)if(!/^[a-z]{2}$/.test(H))throw new $(`--profile-language values must be ISO 639-1 2-letter codes (got "${H}")`);return G}function x(B){if(!B)return[];const G=K(B);for(const H of G)if(!O.has(H))throw new $(`--open-to values must be one or more of proBono,boardMember (got "${H}")`);return G}function q(B,G){if(!B)return[];const H=K(B).map((J)=>J.replace(/^urn:li:[a-z_]+:/,""));for(const J of H)if(!/^\d+$/.test(J))throw new $(`${G} values must be numeric IDs (got "${J}")`);return H}function U(B){const G=["(key:resultType,value:List(PEOPLE))"],H=(Q,V)=>{if(Array.isArray(V)&&V.length)G.push(`(key:${Q},value:List(${V.join(",")}))`)},J=(Q,V)=>{const Z=F(V);if(Z)G.push(`(key:${Q},value:List(${encodeURIComponent(Z)}))`)};J("firstName",B.firstName);J("lastName",B.lastName);J("title",B.title);J("school",B.schoolKeyword);H("network",B.network);H("profileLanguage",B.profileLanguage);H("serviceCategory",B.openTo);H("currentCompany",B.currentCompanyIds);H("pastCompany",B.pastCompanyIds);H("industry",B.industryIds);H("geoUrn",B.geoIds);H("schools",B.schoolIds);return G}function b(B){const G=F(B);if(!G)return"";try{const H=new URL(G,"https://www.linkedin.com"),J=H.hostname.toLowerCase();if(H.protocol!=="https:"||H.username||H.password||H.port)return"";if(J!=="linkedin.com"&&J!=="www.linkedin.com")return"";const Q=H.pathname.match(/^\/in\/([^/?#]+)\/?$/);if(!Q||!Q[1])return"";return`https://www.linkedin.com/in/${Q[1]}/`}catch{return""}}z({site:"linkedin",name:"people-search",access:"read",description:"Search standard LinkedIn (not Sales Navigator) for people by keyword via the Voyager search API. Each invocation consumes against LinkedIn's monthly Commercial Use Limit on people search; throttle accordingly.",domain:N,strategy:C.COOKIE,browser:!0,args:[{name:"keywords",type:"string",required:!0,positional:!0,help:'People search keywords, e.g. "site reliability engineer berlin"'},{name:"limit",type:"int",default:5,help:`Maximum people to return (1-${R}); each query counts toward LinkedIn's monthly CUL`},{name:"first-name",type:"string",required:!1,help:"Filter to people whose first name matches this text (LinkedIn KEYWORDS / FIRST NAME filter)."},{name:"last-name",type:"string",required:!1,help:"Filter to people whose last name matches this text (LinkedIn KEYWORDS / LAST NAME filter)."},{name:"title",type:"string",required:!1,help:"Filter to people whose current title contains this text (LinkedIn KEYWORDS / TITLE filter)."},{name:"school-keyword",type:"string",required:!1,help:"Free-text school filter (LinkedIn SCHOOL filter, name match)."},{name:"network",type:"string",required:!1,help:'Comma-separated connection degrees: 1, 2, 3 (where 3 means 3rd+). E.g. "1,2" for 1st and 2nd-degree only.'},{name:"profile-language",type:"string",required:!1,help:'Comma-separated ISO 639-1 codes for profile language, e.g. "en,fr".'},{name:"open-to",type:"string",required:!1,help:"Comma-separated open-to values: proBono, boardMember."},{name:"current-company-id",type:"string",required:!1,help:'Comma-separated LinkedIn company IDs for CURRENT COMPANY filter (e.g. "1441" for Google). A full URN like `urn:li:fs_company:1441` is also accepted.'},{name:"past-company-id",type:"string",required:!1,help:"Comma-separated LinkedIn company IDs for PAST COMPANY filter. Same lookup pattern as --current-company-id."},{name:"industry-id",type:"string",required:!1,help:'Comma-separated LinkedIn industry IDs (e.g. "4" for Computer Software).'},{name:"location-id",type:"string",required:!1,help:'Comma-separated LinkedIn location IDs (geoUrn numeric tail; e.g. "105214831" for Bengaluru area).'},{name:"school-id",type:"string",required:!1,help:"Comma-separated LinkedIn school IDs (numeric tail of urn:li:fs_school:<id>). For free-text school name matching, use --school-keyword instead."}],columns:["rank","name","headline","location","profile_url"],func:async(B,G)=>{if(!B)throw new M("Browser session required for linkedin people-search");const H=_(G,"keywords","--keywords"),J=S(G.limit),Q=U({firstName:G["first-name"],lastName:G["last-name"],title:G.title,schoolKeyword:G["school-keyword"],network:X(G.network),profileLanguage:D(G["profile-language"]),openTo:x(G["open-to"]),currentCompanyIds:q(G["current-company-id"],"--current-company-id"),pastCompanyIds:q(G["past-company-id"],"--past-company-id"),industryIds:q(G["industry-id"],"--industry-id"),geoIds:q(G["location-id"],"--location-id"),schoolIds:q(G["school-id"],"--school-id")});await B.goto("https://www.linkedin.com/feed/");await B.wait(2);const{rows:V}=await W(B,{keywords:H,filters:Q,start:0,count:Math.max(J,10)},"people-search"),Z=[];for(const Y of V){const j=b(Y.nav);if(!Y.name||!j)continue;Z.push({name:Y.name,headline:Y.headline,location:Y.location,profile_url:j})}if(Z.length===0)throw new P(`No people found for "${H}". The search may have returned zero results, or your monthly Commercial Use Limit may be reached (resets on the 1st).`);return Z.slice(0,J).map((Y,j)=>({rank:j+1,...Y}))}});export const __test__={normalizeWhitespace:F,parseLimit:S,buildPeopleFilters:U,normalizeProfileUrl:b,parseNetworkArg:X,parseProfileLanguageArg:D,parseOpenToArg:x,parseIdListArg:q};
1
+ import{cli as I,Strategy as L}from"@jackwener/opencli/registry";import{ArgumentError as l,CommandExecutionError as C,EmptyResultError as E}from"@jackwener/opencli/errors";import{fetchSearchClusters as N}from"./search-api.js";const b="www.linkedin.com",u=10;function p(e){return String(e??"").replace(/[ ]/g," ").replace(/\s+/g," ").trim()}function O(e,t,r=t){const n=p(e[t]);if(!n)throw new l(`${r} is required`);return n}function f(e){if(e===void 0||e===null||e==="")return 5;const t=Number(e);if(!Number.isInteger(t)||t<1||t>u)throw new l(`--limit must be an integer between 1 and ${u}`);return t}const S={"1":"F","2":"S","3":"O"},A=new Set(["proBono","boardMember"]);function d(e){if(!e)return[];return String(e).split(",").map((t)=>t.trim()).filter(Boolean)}function h(e){if(!e)return[];const t=d(e),r=[];for(const n of t){const o=S[n];if(!o)throw new l(`--network values must be one or more of 1,2,3 (got "${n}")`);if(!r.includes(o))r.push(o)}return r}function y(e){if(!e)return[];const t=d(e).map((r)=>r.toLowerCase());for(const r of t)if(!/^[a-z]{2}$/.test(r))throw new l(`--profile-language values must be ISO 639-1 2-letter codes (got "${r}")`);return t}function w(e){if(!e)return[];const t=d(e);for(const r of t)if(!A.has(r))throw new l(`--open-to values must be one or more of proBono,boardMember (got "${r}")`);return t}function c(e,t){if(!e)return[];const r=d(e).map((n)=>n.replace(/^urn:li:[a-z_]+:/,""));for(const n of r)if(!/^\d+$/.test(n))throw new l(`${t} values must be numeric IDs (got "${n}")`);return r}function g(e){const t=["(key:resultType,value:List(PEOPLE))"],r=(o,i)=>{if(Array.isArray(i)&&i.length)t.push(`(key:${o},value:List(${i.join(",")}))`)},n=(o,i)=>{const a=p(i);if(a)t.push(`(key:${o},value:List(${encodeURIComponent(a)}))`)};n("firstName",e.firstName);n("lastName",e.lastName);n("title",e.title);n("school",e.schoolKeyword);r("network",e.network);r("profileLanguage",e.profileLanguage);r("serviceCategory",e.openTo);r("currentCompany",e.currentCompanyIds);r("pastCompany",e.pastCompanyIds);r("industry",e.industryIds);r("geoUrn",e.geoIds);r("schools",e.schoolIds);return t}function k(e){const t=p(e);if(!t)return"";try{const r=new URL(t,"https://www.linkedin.com"),n=r.hostname.toLowerCase();if(r.protocol!=="https:"||r.username||r.password||r.port)return"";if(n!=="linkedin.com"&&n!=="www.linkedin.com")return"";const o=r.pathname.match(/^\/in\/([^/?#]+)\/?$/);if(!o||!o[1])return"";return`https://www.linkedin.com/in/${o[1]}/`}catch{return""}}I({site:"linkedin",name:"people-search",access:"read",description:"Search standard LinkedIn (not Sales Navigator) for people by keyword via the Voyager search API. Each invocation consumes against LinkedIn's monthly Commercial Use Limit on people search; throttle accordingly.",domain:b,strategy:L.COOKIE,browser:!0,args:[{name:"keywords",type:"string",required:!0,positional:!0,help:'People search keywords, e.g. "site reliability engineer berlin"'},{name:"limit",type:"int",default:5,help:`Maximum people to return (1-${u}); each query counts toward LinkedIn's monthly CUL`},{name:"first-name",type:"string",required:!1,help:"Filter to people whose first name matches this text (LinkedIn KEYWORDS / FIRST NAME filter)."},{name:"last-name",type:"string",required:!1,help:"Filter to people whose last name matches this text (LinkedIn KEYWORDS / LAST NAME filter)."},{name:"title",type:"string",required:!1,help:"Filter to people whose current title contains this text (LinkedIn KEYWORDS / TITLE filter)."},{name:"school-keyword",type:"string",required:!1,help:"Free-text school filter (LinkedIn SCHOOL filter, name match)."},{name:"network",type:"string",required:!1,help:'Comma-separated connection degrees: 1, 2, 3 (where 3 means 3rd+). E.g. "1,2" for 1st and 2nd-degree only.'},{name:"profile-language",type:"string",required:!1,help:'Comma-separated ISO 639-1 codes for profile language, e.g. "en,fr".'},{name:"open-to",type:"string",required:!1,help:"Comma-separated open-to values: proBono, boardMember."},{name:"current-company-id",type:"string",required:!1,help:'Comma-separated LinkedIn company IDs for CURRENT COMPANY filter (e.g. "1441" for Google). A full URN like `urn:li:fs_company:1441` is also accepted.'},{name:"past-company-id",type:"string",required:!1,help:"Comma-separated LinkedIn company IDs for PAST COMPANY filter. Same lookup pattern as --current-company-id."},{name:"industry-id",type:"string",required:!1,help:'Comma-separated LinkedIn industry IDs (e.g. "4" for Computer Software).'},{name:"location-id",type:"string",required:!1,help:'Comma-separated LinkedIn location IDs (geoUrn numeric tail; e.g. "105214831" for Bengaluru area).'},{name:"school-id",type:"string",required:!1,help:"Comma-separated LinkedIn school IDs (numeric tail of urn:li:fs_school:<id>). For free-text school name matching, use --school-keyword instead."}],columns:["rank","name","headline","location","profile_url"],func:async(e,t)=>{if(!e)throw new C("Browser session required for linkedin people-search");const r=O(t,"keywords","--keywords"),n=f(t.limit),o=g({firstName:t["first-name"],lastName:t["last-name"],title:t.title,schoolKeyword:t["school-keyword"],network:h(t.network),profileLanguage:y(t["profile-language"]),openTo:w(t["open-to"]),currentCompanyIds:c(t["current-company-id"],"--current-company-id"),pastCompanyIds:c(t["past-company-id"],"--past-company-id"),industryIds:c(t["industry-id"],"--industry-id"),geoIds:c(t["location-id"],"--location-id"),schoolIds:c(t["school-id"],"--school-id")});await e.goto("https://www.linkedin.com/feed/");await e.wait(2);const{rows:i}=await N(e,{keywords:r,filters:o,start:0,count:Math.max(n,10)},"people-search"),a=[];for(const s of i){const m=k(s.nav);if(!s.name||!m)continue;a.push({name:s.name,headline:s.headline,location:s.location,profile_url:m})}if(a.length===0)throw new E(`No people found for "${r}". The search may have returned zero results, or your monthly Commercial Use Limit may be reached (resets on the 1st).`);return a.slice(0,n).map((s,m)=>({rank:m+1,...s}))}});export const __test__={normalizeWhitespace:p,parseLimit:f,buildPeopleFilters:g,normalizeProfileUrl:k,parseNetworkArg:h,parseProfileLanguageArg:y,parseOpenToArg:w,parseIdListArg:c};
@@ -1 +1 @@
1
- import{cli as R,Strategy as S}from"@jackwener/opencli/registry";import{ArgumentError as W,AuthRequiredError as K,CommandExecutionError as X,EmptyResultError as k}from"@jackwener/opencli/errors";import{LINKEDIN_DOMAIN as b,normalizeWhitespace as q,parseLimit as z,unwrapEvaluateResult as D}from"./shared.js";import{buildReadCommentsScript as N,normalizeThreadUrn as T}from"./social-api.js";const j=20,v=100,x=50;R({site:"linkedin",name:"post-comments",access:"read",description:"List the comments (and nested replies) on a LinkedIn post via the Voyager API. Emits each comment_urn so you can reply to it. Takes a post URL or activity/ugcPost urn.",domain:b,strategy:S.COOKIE,browser:!0,args:[{name:"post",type:"string",required:!0,positional:!0,help:"Post to read comments from: a LinkedIn post URL (…/feed/update/… or …/posts/…) or a raw urn:li:activity:… / urn:li:ugcPost:… urn."},{name:"limit",type:"int",required:!1,default:j,help:`Maximum comments to return (1-${v}).`},{name:"sort",type:"string",required:!1,default:"relevance",help:"Comment order: relevance (default) or recent (chronological)."}],columns:["rank","comment_urn","author","headline","text","created_at","is_reply","parent_comment_urn","reactions","permalink"],func:async(J,Q)=>{if(!J)throw new X("Browser session required for linkedin post-comments");const V=T(Q?.post),F=z(Q?.limit,j,v),G=String(Q?.sort??"relevance").trim().toLowerCase();if(G!=="relevance"&&G!=="recent")throw new W("--sort 只能是 relevance 或 recent");const C=G==="recent"?"CHRONOLOGICAL":"RELEVANCE";await J.goto(`https://www.linkedin.com/feed/update/${V}/`);await J.wait(2);const Y=[],O=new Set;for(let $=0;Y.length<F&&$<v;$+=x){const H=Math.min(x,F-Y.length),B=D(await J.evaluate(N({activityUrn:V,count:H,start:$,sortOrder:C})));if(!B?.ok){if(B?.stage==="auth"||B?.httpStatus===401||B?.httpStatus===403)throw new K(b,`LinkedIn post-comments requires an active signed-in LinkedIn browser session (${B?.error||"auth"}).`);throw new X(`LinkedIn post-comments failed: stage=${B?.stage||"read"} http=${B?.httpStatus||"?"} ${B?.error||""}`.trim())}const Z=Array.isArray(B.rows)?B.rows:[];if(Z.length===0)break;for(const f of Z){const P=f.comment_urn||`${f.author}::${f.created_at}::${(f.text||"").slice(0,40)}`;if(O.has(P))continue;O.add(P);Y.push({comment_urn:f.comment_urn||"",author:q(f.author),headline:q(f.headline),text:q(f.text),created_at:f.created_at?new Date(f.created_at).toISOString():"",is_reply:f.is_reply?"yes":"",parent_comment_urn:f.parent_comment_urn||"",reactions:Number(f.reactions)||0,permalink:U(f.permalink)})}if(Z.length<H)break}if(Y.length===0)throw new k("linkedin post-comments","This post has no comments, or comments are not visible to your account.");return Y.slice(0,F).map(($,H)=>({rank:H+1,...$}))}});function U(J){const Q=q(J);if(!Q)return"";try{const V=new URL(Q,"https://www.linkedin.com");if(V.protocol!=="https:")return"";return V.toString()}catch{return""}}
1
+ import{cli as g,Strategy as L}from"@jackwener/opencli/registry";import{ArgumentError as I,AuthRequiredError as E,CommandExecutionError as w,EmptyResultError as v}from"@jackwener/opencli/errors";import{LINKEDIN_DOMAIN as f,normalizeWhitespace as c,parseLimit as A,unwrapEvaluateResult as S}from"./shared.js";import{buildReadCommentsScript as R,normalizeThreadUrn as b}from"./social-api.js";const y=20,p=100,_=50;g({site:"linkedin",name:"post-comments",access:"read",description:"List the comments (and nested replies) on a LinkedIn post via the Voyager API. Emits each comment_urn so you can reply to it. Takes a post URL or activity/ugcPost urn.",domain:f,strategy:L.COOKIE,browser:!0,args:[{name:"post",type:"string",required:!0,positional:!0,help:"Post to read comments from: a LinkedIn post URL (…/feed/update/… or …/posts/…) or a raw urn:li:activity:… / urn:li:ugcPost:… urn."},{name:"limit",type:"int",required:!1,default:y,help:`Maximum comments to return (1-${p}).`},{name:"sort",type:"string",required:!1,default:"relevance",help:"Comment order: relevance (default) or recent (chronological)."}],columns:["rank","comment_urn","author","headline","text","created_at","is_reply","parent_comment_urn","reactions","permalink"],func:async(r,n)=>{if(!r)throw new w("Browser session required for linkedin post-comments");const o=b(n?.post),m=A(n?.limit,y,p),u=String(n?.sort??"relevance").trim().toLowerCase();if(u!=="relevance"&&u!=="recent")throw new I("--sort 只能是 relevance 或 recent");const k=u==="recent"?"CHRONOLOGICAL":"RELEVANCE";await r.goto(`https://www.linkedin.com/feed/update/${o}/`);await r.wait(2);const a=[],d=new Set;for(let i=0;a.length<m&&i<p;i+=_){const s=Math.min(_,m-a.length),e=S(await r.evaluate(R({activityUrn:o,count:s,start:i,sortOrder:k})));if(!e?.ok){if(e?.stage==="auth"||e?.httpStatus===401||e?.httpStatus===403)throw new E(f,`LinkedIn post-comments requires an active signed-in LinkedIn browser session (${e?.error||"auth"}).`);throw new w(`LinkedIn post-comments failed: stage=${e?.stage||"read"} http=${e?.httpStatus||"?"} ${e?.error||""}`.trim())}const l=Array.isArray(e.rows)?e.rows:[];if(l.length===0)break;for(const t of l){const h=t.comment_urn||`${t.author}::${t.created_at}::${(t.text||"").slice(0,40)}`;if(d.has(h))continue;d.add(h);a.push({comment_urn:t.comment_urn||"",author:c(t.author),headline:c(t.headline),text:c(t.text),created_at:t.created_at?new Date(t.created_at).toISOString():"",is_reply:t.is_reply?"yes":"",parent_comment_urn:t.parent_comment_urn||"",reactions:Number(t.reactions)||0,permalink:C(t.permalink)})}if(l.length<s)break}if(a.length===0)throw new v("linkedin post-comments","This post has no comments, or comments are not visible to your account.");return a.slice(0,m).map((i,s)=>({rank:s+1,...i}))}});function C(r){const n=c(r);if(!n)return"";try{const o=new URL(n,"https://www.linkedin.com");if(o.protocol!=="https:")return"";return o.toString()}catch{return""}}
@@ -1 +1 @@
1
- import{cli as X,Strategy as Y}from"@jackwener/opencli/registry";import{AuthRequiredError as Z,CommandExecutionError as J,EmptyResultError as $}from"@jackwener/opencli/errors";import{LINKEDIN_DOMAIN as Q,normalizeWhitespace as F,unwrapEvaluateResult as b}from"./shared.js";import{buildPostDetailScript as q,normalizeThreadUrn as P}from"./social-api.js";X({site:"linkedin",name:"post-detail",access:"read",description:"Read one LinkedIn post via the Voyager API: author, body text, reactions/comments/reposts/impressions, and whether it is a repost. Takes a post URL or activity/ugcPost urn.",domain:Q,strategy:Y.COOKIE,browser:!0,args:[{name:"post",type:"string",required:!0,positional:!0,help:"Post to read: a LinkedIn post URL (…/feed/update/… or …/posts/…) or a raw urn:li:activity:… / urn:li:ugcPost:… urn."}],columns:["post_urn","author","author_type","author_url","posted","text","content_type","is_repost","reactions","comments","reposts","impressions","url"],func:async(G,V)=>{if(!G)throw new J("Browser session required for linkedin post-detail");const H=P(V?.post);await G.goto("https://www.linkedin.com/feed/");await G.wait(2);const B=b(await G.evaluate(q({activityUrn:H})));if(!B?.ok){if(B?.stage==="auth"||B?.httpStatus===401||B?.httpStatus===403)throw new Z(Q,`LinkedIn post-detail requires an active signed-in LinkedIn browser session (${B?.error||"auth"}).`);throw new J(`LinkedIn post-detail failed: stage=${B?.stage||"read"} http=${B?.httpStatus||"?"} ${B?.error||""}`.trim())}const f=B.post||{};if(!f.author&&!f.text)throw new $("linkedin post-detail","The post was not found or is not visible to your account.");return[{post_urn:f.post_urn||H,author:F(f.author),author_type:f.author_type||"",author_url:F(f.author_url),posted:F(f.posted).replace(/[•·|\s]+$/,""),text:F(f.text),content_type:f.content_type||"",is_repost:f.is_repost||"",reactions:Number(f.reactions)||0,comments:Number(f.comments)||0,reposts:Number(f.reposts)||0,impressions:Number(f.impressions)||0,url:F(f.url)}]}});
1
+ import{cli as u,Strategy as p}from"@jackwener/opencli/registry";import{AuthRequiredError as d,CommandExecutionError as i,EmptyResultError as m}from"@jackwener/opencli/errors";import{LINKEDIN_DOMAIN as n,normalizeWhitespace as r,unwrapEvaluateResult as c}from"./shared.js";import{buildPostDetailScript as l,normalizeThreadUrn as h}from"./social-api.js";u({site:"linkedin",name:"post-detail",access:"read",description:"Read one LinkedIn post via the Voyager API: author, body text, reactions/comments/reposts/impressions, and whether it is a repost. Takes a post URL or activity/ugcPost urn.",domain:n,strategy:p.COOKIE,browser:!0,args:[{name:"post",type:"string",required:!0,positional:!0,help:"Post to read: a LinkedIn post URL (…/feed/update/… or …/posts/…) or a raw urn:li:activity:… / urn:li:ugcPost:… urn."}],columns:["post_urn","author","author_type","author_url","posted","text","content_type","is_repost","reactions","comments","reposts","impressions","url"],func:async(o,a)=>{if(!o)throw new i("Browser session required for linkedin post-detail");const s=h(a?.post);await o.goto("https://www.linkedin.com/feed/");await o.wait(2);const e=c(await o.evaluate(l({activityUrn:s})));if(!e?.ok){if(e?.stage==="auth"||e?.httpStatus===401||e?.httpStatus===403)throw new d(n,`LinkedIn post-detail requires an active signed-in LinkedIn browser session (${e?.error||"auth"}).`);throw new i(`LinkedIn post-detail failed: stage=${e?.stage||"read"} http=${e?.httpStatus||"?"} ${e?.error||""}`.trim())}const t=e.post||{};if(!t.author&&!t.text)throw new m("linkedin post-detail","The post was not found or is not visible to your account.");return[{post_urn:t.post_urn||s,author:r(t.author),author_type:t.author_type||"",author_url:r(t.author_url),posted:r(t.posted).replace(/[•·|\s]+$/,""),text:r(t.text),content_type:t.content_type||"",is_repost:t.is_repost||"",reactions:Number(t.reactions)||0,comments:Number(t.comments)||0,reposts:Number(t.reposts)||0,impressions:Number(t.impressions)||0,url:r(t.url)}]}});
@@ -1 +1 @@
1
- import{cli as F,Strategy as G}from"@jackwener/opencli/registry";import{CommandExecutionError as H,EmptyResultError as J}from"@jackwener/opencli/errors";import{normalizeWhitespace as v}from"./shared.js";import{fetchSelfAnalytics as K,normalizeProfileInputUrl as L}from"./profile-api.js";F({site:"linkedin",name:"profile-analytics",access:"read",description:"Read your own LinkedIn analytics via the Voyager API: profile views, search appearances, followers, and connections (self only)",domain:"www.linkedin.com",strategy:G.COOKIE,browser:!0,args:[{name:"profile-url",type:"string",required:!1,help:"Ignored beyond validation — analytics are only visible for the signed-in account."}],columns:["profile_url","profile_views","post_impressions","search_appearances","followers","connections"],func:async(B,D)=>{if(!B)throw new H("Browser session required for linkedin profile-analytics");if(D["profile-url"])L(D["profile-url"],"profile-analytics");const q=await K(B,"profile-analytics"),b={profile_url:"https://www.linkedin.com/in/me/",profile_views:v(q.profile_views),post_impressions:"",search_appearances:v(q.search_appearances),followers:v(q.followers),connections:v(q.connections)};if(!b.profile_views&&!b.search_appearances&&!b.followers&&!b.connections)throw new J("linkedin profile-analytics","No LinkedIn analytics counters were returned by the Voyager API.");return[b]}});export const __test__={};
1
+ import{cli as s,Strategy as a}from"@jackwener/opencli/registry";import{CommandExecutionError as l,EmptyResultError as t}from"@jackwener/opencli/errors";import{normalizeWhitespace as o}from"./shared.js";import{fetchSelfAnalytics as c,normalizeProfileInputUrl as p}from"./profile-api.js";s({site:"linkedin",name:"profile-analytics",access:"read",description:"Read your own LinkedIn analytics via the Voyager API: profile views, search appearances, followers, and connections (self only)",domain:"www.linkedin.com",strategy:a.COOKIE,browser:!0,args:[{name:"profile-url",type:"string",required:!1,help:"Ignored beyond validation — analytics are only visible for the signed-in account."}],columns:["profile_url","profile_views","post_impressions","search_appearances","followers","connections"],func:async(i,n)=>{if(!i)throw new l("Browser session required for linkedin profile-analytics");if(n["profile-url"])p(n["profile-url"],"profile-analytics");const r=await c(i,"profile-analytics"),e={profile_url:"https://www.linkedin.com/in/me/",profile_views:o(r.profile_views),post_impressions:"",search_appearances:o(r.search_appearances),followers:o(r.followers),connections:o(r.connections)};if(!e.profile_views&&!e.search_appearances&&!e.followers&&!e.connections)throw new t("linkedin profile-analytics","No LinkedIn analytics counters were returned by the Voyager API.");return[e]}});export const __test__={};
@@ -1,4 +1,4 @@
1
- import{AuthRequiredError as Z,CommandExecutionError as $}from"@jackwener/opencli/errors";import{assertSafeLinkedinUrl as z,normalizeWhitespace as G,unwrapEvaluateResult as B}from"./shared.js";const W="com.linkedin.voyager.dash.deco.identity.profile.FullProfileWithEntities-101",y="com.linkedin.voyager.dash.deco.identity.profile.FullProfilePositionGroup-58",N=/^\/in\/[^/?#]+\/?$/;export function normalizeProfileInputUrl(J,X){const K=z(J||"https://www.linkedin.com/in/me/","profile-url","/in/me/"),Q=new URL(K);if(!N.test(Q.pathname))throw new $(`LinkedIn ${X} requires a /in/<handle>/ profile URL`);return Q.toString()}const T=String.raw`
1
+ import{AuthRequiredError as s,CommandExecutionError as a}from"@jackwener/opencli/errors";import{assertSafeLinkedinUrl as m,normalizeWhitespace as y,unwrapEvaluateResult as l}from"./shared.js";const u="com.linkedin.voyager.dash.deco.identity.profile.FullProfileWithEntities-101",f="com.linkedin.voyager.dash.deco.identity.profile.FullProfilePositionGroup-58",w=/^\/in\/[^/?#]+\/?$/;export function normalizeProfileInputUrl(e,o){const n=m(e||"https://www.linkedin.com/in/me/","profile-url","/in/me/"),t=new URL(n);if(!w.test(t.pathname))throw new a(`LinkedIn ${o} requires a /in/<handle>/ profile URL`);return t.toString()}const h=String.raw`
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
  const H = {
@@ -60,18 +60,18 @@ import{AuthRequiredError as Z,CommandExecutionError as $}from"@jackwener/opencli
60
60
  const dateRange = start || endLabel ? norm((start + ' – ' + endLabel).replace(/^ – | – $/g, '').trim()) : '';
61
61
  return { startDate: start, endDate: endLabel, dateRange };
62
62
  }
63
- `;function H(J,X){const K=Object.entries(J).map(([Q,Y])=>`const ${Q} = ${JSON.stringify(Y)};`).join(`
63
+ `;function c(e,o){const n=Object.entries(e).map(([t,i])=>`const ${t} = ${JSON.stringify(i)};`).join(`
64
64
  `);return`(async () => {
65
- ${T}
66
- ${K}
67
- ${X}
68
- })()`}async function j(J,X,K){await J.goto(X);await J.wait(3);const Q=B(await J.evaluate(String.raw`(() => {
65
+ ${h}
66
+ ${n}
67
+ ${o}
68
+ })()`}async function p(e,o,n){await e.goto(o);await e.wait(3);const t=l(await e.evaluate(String.raw`(() => {
69
69
  const path = String(location.pathname || '');
70
70
  const authWall = /linkedin\.com\/(?:login|checkpoint|authwall|uas)/i.test(location.href)
71
71
  || Boolean(document.querySelector('input[name="session_key"], form.login__form'));
72
72
  const m = path.match(/^\/in\/([^/?#]+)\/?$/);
73
73
  return { publicId: m ? decodeURIComponent(m[1]) : '', authWall };
74
- })()`));if(Q?.authWall)throw new Z("linkedin.com",`LinkedIn ${K} requires an active signed-in browser session`);const Y=G(Q?.publicId);if(!Y||Y==="me")throw new $(`LinkedIn ${K} could not resolve the profile handle from ${X}`);return{publicId:Y,profileUrl:`https://www.linkedin.com/in/${Y}/`}}export async function fetchFullProfile(J,X,K){const{publicId:Q,profileUrl:Y}=await j(J,X,K),V=B(await J.evaluate(H({PUBLIC_ID:Q,DECO:W},String.raw`
74
+ })()`));if(t?.authWall)throw new s("linkedin.com",`LinkedIn ${n} requires an active signed-in browser session`);const i=y(t?.publicId);if(!i||i==="me")throw new a(`LinkedIn ${n} could not resolve the profile handle from ${o}`);return{publicId:i,profileUrl:`https://www.linkedin.com/in/${i}/`}}export async function fetchFullProfile(e,o,n){const{publicId:t,profileUrl:i}=await p(e,o,n),r=l(await e.evaluate(c({PUBLIC_ID:t,DECO:u},String.raw`
75
75
  const r = await voyagerGet('/identity/dash/profiles?q=memberIdentity&memberIdentity=' + encodeURIComponent(PUBLIC_ID) + '&decorationId=' + DECO);
76
76
  if (!r.ok) return { ok: false, auth: r.auth || false, status: r.status || 0 };
77
77
  const byUrn = indexIncluded(r.json);
@@ -120,13 +120,13 @@ ${X}
120
120
  },
121
121
  positions, educations,
122
122
  };
123
- `)));if(V?.auth)throw new Z("linkedin.com",`LinkedIn ${K} requires an active signed-in browser session`);if(!V?.ok)throw new $(`LinkedIn ${K}: profile API returned ${V?.empty?"no profile entity":"HTTP "+(V?.status||"?")}`);return{...V,profileUrl:Y,publicId:Q}}export async function fetchExperience(J,X,K){const{publicId:Q,profileUrl:Y}=await j(J,X,K),V=B(await J.evaluate(H({PUBLIC_ID:Q,DECO:W},String.raw`
123
+ `)));if(r?.auth)throw new s("linkedin.com",`LinkedIn ${n} requires an active signed-in browser session`);if(!r?.ok)throw new a(`LinkedIn ${n}: profile API returned ${r?.empty?"no profile entity":"HTTP "+(r?.status||"?")}`);return{...r,profileUrl:i,publicId:t}}export async function fetchExperience(e,o,n){const{publicId:t,profileUrl:i}=await p(e,o,n),r=l(await e.evaluate(c({PUBLIC_ID:t,DECO:u},String.raw`
124
124
  const r = await voyagerGet('/identity/dash/profiles?q=memberIdentity&memberIdentity=' + encodeURIComponent(PUBLIC_ID) + '&decorationId=' + DECO);
125
125
  if (!r.ok) return { ok: false, auth: r.auth || false, status: r.status || 0 };
126
126
  const byUrn = indexIncluded(r.json);
127
127
  const profile = pickType(byUrn, 'identity.profile.Profile')[0] || null;
128
128
  return { ok: !!profile, profileUrn: profile ? profile.entityUrn : '' };
129
- `)));if(V?.auth)throw new Z("linkedin.com",`LinkedIn ${K} requires an active signed-in browser session`);if(!V?.ok||!V?.profileUrn)throw new $(`LinkedIn ${K}: could not resolve profile urn (HTTP ${V?.status||"?"})`);const M=B(await J.evaluate(H({PROFILE_URN:V.profileUrn,DECO:y},String.raw`
129
+ `)));if(r?.auth)throw new s("linkedin.com",`LinkedIn ${n} requires an active signed-in browser session`);if(!r?.ok||!r?.profileUrn)throw new a(`LinkedIn ${n}: could not resolve profile urn (HTTP ${r?.status||"?"})`);const d=l(await e.evaluate(c({PROFILE_URN:r.profileUrn,DECO:f},String.raw`
130
130
  const r = await voyagerGet('/identity/dash/profilePositionGroups?q=viewee&profileUrn=' + encodeURIComponent(PROFILE_URN) + '&decorationId=' + DECO);
131
131
  if (!r.ok) return { ok: false, auth: r.auth || false, status: r.status || 0 };
132
132
  const byUrn = indexIncluded(r.json);
@@ -152,7 +152,7 @@ ${X}
152
152
  }
153
153
  }
154
154
  return { ok: true, rows };
155
- `)));if(M?.auth)throw new Z("linkedin.com",`LinkedIn ${K} requires an active signed-in browser session`);if(!M?.ok)throw new $(`LinkedIn ${K}: positionGroups API returned HTTP ${M?.status||"?"}`);return{rows:Array.isArray(M.rows)?M.rows:[],profileUrl:Y,publicId:Q}}export async function fetchProjects(J,X,K){const{profileUrl:Q}=await j(J,X,K),Y=B(await J.evaluate(H({DECO:W},String.raw`
155
+ `)));if(d?.auth)throw new s("linkedin.com",`LinkedIn ${n} requires an active signed-in browser session`);if(!d?.ok)throw new a(`LinkedIn ${n}: positionGroups API returned HTTP ${d?.status||"?"}`);return{rows:Array.isArray(d.rows)?d.rows:[],profileUrl:i,publicId:t}}export async function fetchProjects(e,o,n){const{profileUrl:t}=await p(e,o,n),i=l(await e.evaluate(c({DECO:u},String.raw`
156
156
  const path = String(location.pathname || '').match(/^\/in\/([^/?#]+)/);
157
157
  const pid = path ? decodeURIComponent(path[1]) : '';
158
158
  const r = await voyagerGet('/identity/dash/profiles?q=memberIdentity&memberIdentity=' + encodeURIComponent(pid) + '&decorationId=' + DECO);
@@ -160,7 +160,7 @@ ${X}
160
160
  const byUrn = indexIncluded(r.json);
161
161
  const profile = pickType(byUrn, 'identity.profile.Profile')[0] || null;
162
162
  return { ok: !!profile, profileUrn: profile ? profile.entityUrn : '' };
163
- `)));if(Y?.auth)throw new Z("linkedin.com",`LinkedIn ${K} requires an active signed-in browser session`);if(!Y?.ok||!Y?.profileUrn)throw new $(`LinkedIn ${K}: could not resolve profile urn (HTTP ${Y?.status||"?"})`);const V=B(await J.evaluate(H({PROFILE_URN:Y.profileUrn},String.raw`
163
+ `)));if(i?.auth)throw new s("linkedin.com",`LinkedIn ${n} requires an active signed-in browser session`);if(!i?.ok||!i?.profileUrn)throw new a(`LinkedIn ${n}: could not resolve profile urn (HTTP ${i?.status||"?"})`);const r=l(await e.evaluate(c({PROFILE_URN:i.profileUrn},String.raw`
164
164
  const r = await voyagerGet('/identity/dash/profileProjects?q=viewee&profileUrn=' + encodeURIComponent(PROFILE_URN) + '&count=50');
165
165
  if (!r.ok) return { ok: false, auth: r.auth || false, status: r.status || 0 };
166
166
  const byUrn = indexIncluded(r.json);
@@ -176,7 +176,7 @@ ${X}
176
176
  };
177
177
  });
178
178
  return { ok: true, rows };
179
- `)));if(V?.auth)throw new Z("linkedin.com",`LinkedIn ${K} requires an active signed-in browser session`);if(!V?.ok)throw new $(`LinkedIn ${K}: profileProjects API returned HTTP ${V?.status||"?"}`);return{rows:Array.isArray(V.rows)?V.rows:[],profileUrl:Q}}export async function fetchSelfAnalytics(J,X){await J.goto("https://www.linkedin.com/feed/");await J.wait(2);if(B(await J.evaluate(String.raw`(() => /linkedin\.com\/(?:login|checkpoint|authwall|uas)/i.test(location.href) || Boolean(document.querySelector('input[name="session_key"]')))()`)))throw new Z("linkedin.com",`LinkedIn ${X} requires an active signed-in browser session`);const Q=B(await J.evaluate(H({DECO:W},String.raw`
179
+ `)));if(r?.auth)throw new s("linkedin.com",`LinkedIn ${n} requires an active signed-in browser session`);if(!r?.ok)throw new a(`LinkedIn ${n}: profileProjects API returned HTTP ${r?.status||"?"}`);return{rows:Array.isArray(r.rows)?r.rows:[],profileUrl:t}}export async function fetchSelfAnalytics(e,o){await e.goto("https://www.linkedin.com/feed/");await e.wait(2);if(l(await e.evaluate(String.raw`(() => /linkedin\.com\/(?:login|checkpoint|authwall|uas)/i.test(location.href) || Boolean(document.querySelector('input[name="session_key"]')))()`)))throw new s("linkedin.com",`LinkedIn ${o} requires an active signed-in browser session`);const t=l(await e.evaluate(c({DECO:u},String.raw`
180
180
  const result = { profile_views: '', search_appearances: '', followers: '', connections: '' };
181
181
  // 资料浏览量 / 搜索出现次数
182
182
  const wvmp = await voyagerGet('/identity/wvmpCards');
@@ -215,4 +215,4 @@ ${X}
215
215
  }
216
216
  }
217
217
  return { ok: true, result };
218
- `)));if(Q?.auth)throw new Z("linkedin.com",`LinkedIn ${X} requires an active signed-in browser session`);if(!Q?.ok)throw new $(`LinkedIn ${X}: analytics API unavailable`);return Q.result}export const __test__={normalizeProfileInputUrl,DECO_FULL_PROFILE:W,DECO_POSITION_GROUPS:y};
218
+ `)));if(t?.auth)throw new s("linkedin.com",`LinkedIn ${o} requires an active signed-in browser session`);if(!t?.ok)throw new a(`LinkedIn ${o}: analytics API unavailable`);return t.result}export const __test__={normalizeProfileInputUrl,DECO_FULL_PROFILE:u,DECO_POSITION_GROUPS:f};
@@ -1 +1 @@
1
- import{cli as Q,Strategy as T}from"@jackwener/opencli/registry";import{CommandExecutionError as V,EmptyResultError as X}from"@jackwener/opencli/errors";import{normalizeWhitespace as A}from"./shared.js";import{fetchExperience as Y,normalizeProfileInputUrl as Z}from"./profile-api.js";function L(q,F,G,H){const B=A(q.title);return{rank:F+1,total_count:G,title:B,employment_type:"",company:A(q.company),date_range:A(q.dateRange),start_date:A(q.startDate),end_date:A(q.endDate),location:A(q.location),location_type:"",description:A(q.description),skills:"",media:"",urls:"",skill_url:"",media_url:"",profile_url:H,raw_text:[B,A(q.company),A(q.dateRange),A(q.location),A(q.description)].filter(Boolean).join(" | ")}}Q({site:"linkedin",name:"profile-experience",access:"read",description:"Read LinkedIn profile experience entries via the Voyager API: titles, companies, dates, locations, and descriptions",domain:"www.linkedin.com",strategy:T.COOKIE,browser:!0,args:[{name:"profile-url",type:"string",required:!1,help:"LinkedIn /in/<handle>/ profile URL. Defaults to /in/me/."}],columns:["rank","total_count","title","employment_type","company","date_range","start_date","end_date","location","location_type","description","skills","media","urls","skill_url","media_url","profile_url","raw_text"],func:async(q,F)=>{if(!q)throw new V("Browser session required for linkedin profile-experience");const G=Z(F["profile-url"],"profile-experience"),{rows:H,profileUrl:B}=await Y(q,G,"profile-experience"),J=H.filter((K)=>A(K.title));if(J.length===0)throw new X("linkedin profile-experience","No LinkedIn profile experience entries were returned by the Voyager API.");return J.map((K,N)=>L(K,N,J.length,B))}});export const __test__={buildRow:L};
1
+ import{cli as c,Strategy as d}from"@jackwener/opencli/registry";import{CommandExecutionError as m,EmptyResultError as f}from"@jackwener/opencli/errors";import{normalizeWhitespace as t}from"./shared.js";import{fetchExperience as u,normalizeProfileInputUrl as _}from"./profile-api.js";function p(e,r,n,o){const i=t(e.title);return{rank:r+1,total_count:n,title:i,employment_type:"",company:t(e.company),date_range:t(e.dateRange),start_date:t(e.startDate),end_date:t(e.endDate),location:t(e.location),location_type:"",description:t(e.description),skills:"",media:"",urls:"",skill_url:"",media_url:"",profile_url:o,raw_text:[i,t(e.company),t(e.dateRange),t(e.location),t(e.description)].filter(Boolean).join(" | ")}}c({site:"linkedin",name:"profile-experience",access:"read",description:"Read LinkedIn profile experience entries via the Voyager API: titles, companies, dates, locations, and descriptions",domain:"www.linkedin.com",strategy:d.COOKIE,browser:!0,args:[{name:"profile-url",type:"string",required:!1,help:"LinkedIn /in/<handle>/ profile URL. Defaults to /in/me/."}],columns:["rank","total_count","title","employment_type","company","date_range","start_date","end_date","location","location_type","description","skills","media","urls","skill_url","media_url","profile_url","raw_text"],func:async(e,r)=>{if(!e)throw new m("Browser session required for linkedin profile-experience");const n=_(r["profile-url"],"profile-experience"),{rows:o,profileUrl:i}=await u(e,n,"profile-experience"),l=o.filter((a)=>t(a.title));if(l.length===0)throw new f("linkedin profile-experience","No LinkedIn profile experience entries were returned by the Voyager API.");return l.map((a,s)=>p(a,s,l.length,i))}});export const __test__={buildRow:p};
@@ -1 +1 @@
1
- import{cli as M,Strategy as N}from"@jackwener/opencli/registry";import{CommandExecutionError as O,EmptyResultError as Q}from"@jackwener/opencli/errors";import{normalizeWhitespace as A}from"./shared.js";import{fetchProjects as T,normalizeProfileInputUrl as V}from"./profile-api.js";function J(q,D,F){const B=A(q.title);return{rank:D+1,title:B,date_range:A(q.dateRange),associated_with:"",description:A(q.description),skills:"",media:"",urls:"",profile_url:F,raw_text:[B,A(q.dateRange),A(q.description)].filter(Boolean).join(" | ")}}M({site:"linkedin",name:"profile-projects",access:"read",description:"Read LinkedIn profile projects via the Voyager API: titles, dates, and descriptions",domain:"www.linkedin.com",strategy:N.COOKIE,browser:!0,args:[{name:"profile-url",type:"string",required:!1,help:"LinkedIn /in/<handle>/ profile URL. Defaults to /in/me/."}],columns:["rank","title","date_range","associated_with","description","skills","media","urls","profile_url","raw_text"],func:async(q,D)=>{if(!q)throw new O("Browser session required for linkedin profile-projects");const F=V(D["profile-url"],"profile-projects"),{rows:B,profileUrl:K}=await T(q,F,"profile-projects"),H=B.filter((G)=>A(G.title));if(H.length===0)throw new Q("linkedin profile-projects","No LinkedIn profile projects were returned by the Voyager API.");return H.map((G,L)=>J(G,L,K))}});export const __test__={buildRow:J};
1
+ import{cli as d,Strategy as c}from"@jackwener/opencli/registry";import{CommandExecutionError as f,EmptyResultError as m}from"@jackwener/opencli/errors";import{normalizeWhitespace as r}from"./shared.js";import{fetchProjects as u,normalizeProfileInputUrl as w}from"./profile-api.js";function s(e,i,o){const t=r(e.title);return{rank:i+1,title:t,date_range:r(e.dateRange),associated_with:"",description:r(e.description),skills:"",media:"",urls:"",profile_url:o,raw_text:[t,r(e.dateRange),r(e.description)].filter(Boolean).join(" | ")}}d({site:"linkedin",name:"profile-projects",access:"read",description:"Read LinkedIn profile projects via the Voyager API: titles, dates, and descriptions",domain:"www.linkedin.com",strategy:c.COOKIE,browser:!0,args:[{name:"profile-url",type:"string",required:!1,help:"LinkedIn /in/<handle>/ profile URL. Defaults to /in/me/."}],columns:["rank","title","date_range","associated_with","description","skills","media","urls","profile_url","raw_text"],func:async(e,i)=>{if(!e)throw new f("Browser session required for linkedin profile-projects");const o=w(i["profile-url"],"profile-projects"),{rows:t,profileUrl:a}=await u(e,o,"profile-projects"),l=t.filter((n)=>r(n.title));if(l.length===0)throw new m("linkedin profile-projects","No LinkedIn profile projects were returned by the Voyager API.");return l.map((n,p)=>s(n,p,a))}});export const __test__={buildRow:s};
@@ -1,3 +1,3 @@
1
- import{cli as $,Strategy as v}from"@jackwener/opencli/registry";import{CommandExecutionError as N}from"@jackwener/opencli/errors";import{compactRepeatedText as Q,normalizeWhitespace as A}from"./shared.js";import{fetchFullProfile as D,normalizeProfileInputUrl as F}from"./profile-api.js";function V(q){const B=[A(q.title),A(q.company)].filter(Boolean).join(" — "),G=[A(q.location),A(q.dateRange)].filter(Boolean).join(" · ");return[B,G].filter(Boolean).join(" (")+(G?")":"")}function X(q){const B=A(q.school),H=[[A(q.degree),A(q.field)].filter(Boolean).join(", "),A(q.dateRange)].filter(Boolean).join(" · ");return[B,H].filter(Boolean).join(" (")+(H?")":"")}$({site:"linkedin",name:"profile-read",access:"read",description:"Read LinkedIn profile sections via the Voyager API: name, headline, location, About, experience, and education",domain:"www.linkedin.com",strategy:v.COOKIE,browser:!0,args:[{name:"profile-url",type:"string",required:!1,help:"LinkedIn /in/<handle>/ profile URL. Defaults to /in/me/."}],columns:["profile_url","name","headline","location","about","about_character_count","about_skills","experience","education","services","featured"],func:async(q,B)=>{if(!q)throw new N("Browser session required for linkedin profile-read");const G=F(B["profile-url"],"profile-read"),H=await D(q,G,"profile-read"),{profile:J,positions:Y,educations:Z}=H,K=Q([J.firstName,J.lastName].filter(Boolean).join(" "));if(!K)throw new N("LinkedIn profile-read could not find a profile name");const L=A(J.summary);return[{profile_url:H.profileUrl,name:K,headline:Q(J.headline),location:A(J.location),about:L,about_character_count:`${L.length}/2,600`,about_skills:"",experience:Y.map(V).filter(Boolean).join(`
2
- `),education:Z.map(X).filter(Boolean).join(`
3
- `),services:"",featured:""}]}});export const __test__={fmtPosition:V,fmtEducation:X};
1
+ import{cli as p,Strategy as h}from"@jackwener/opencli/registry";import{CommandExecutionError as c}from"@jackwener/opencli/errors";import{compactRepeatedText as s,normalizeWhitespace as o}from"./shared.js";import{fetchFullProfile as _,normalizeProfileInputUrl as w}from"./profile-api.js";function f(e){const i=[o(e.title),o(e.company)].filter(Boolean).join(" — "),n=[o(e.location),o(e.dateRange)].filter(Boolean).join(" · ");return[i,n].filter(Boolean).join(" (")+(n?")":"")}function d(e){const i=o(e.school),t=[[o(e.degree),o(e.field)].filter(Boolean).join(", "),o(e.dateRange)].filter(Boolean).join(" · ");return[i,t].filter(Boolean).join(" (")+(t?")":"")}p({site:"linkedin",name:"profile-read",access:"read",description:"Read LinkedIn profile sections via the Voyager API: name, headline, location, About, experience, and education",domain:"www.linkedin.com",strategy:h.COOKIE,browser:!0,args:[{name:"profile-url",type:"string",required:!1,help:"LinkedIn /in/<handle>/ profile URL. Defaults to /in/me/."}],columns:["profile_url","name","headline","location","about","about_character_count","about_skills","experience","education","services","featured"],func:async(e,i)=>{if(!e)throw new c("Browser session required for linkedin profile-read");const n=w(i["profile-url"],"profile-read"),t=await _(e,n,"profile-read"),{profile:r,positions:u,educations:m}=t,a=s([r.firstName,r.lastName].filter(Boolean).join(" "));if(!a)throw new c("LinkedIn profile-read could not find a profile name");const l=o(r.summary);return[{profile_url:t.profileUrl,name:a,headline:s(r.headline),location:o(r.location),about:l,about_character_count:`${l.length}/2,600`,about_skills:"",experience:u.map(f).filter(Boolean).join(`
2
+ `),education:m.map(d).filter(Boolean).join(`
3
+ `),services:"",featured:""}]}});export const __test__={fmtPosition:f,fmtEducation:d};
@@ -1 +1 @@
1
- import{cli as b,Strategy as q}from"@jackwener/opencli/registry";import{ArgumentError as W,AuthRequiredError as v,CommandExecutionError as Y}from"@jackwener/opencli/errors";import{assertLinkedInAuthenticated as z,LINKEDIN_DOMAIN as Z,unwrapEvaluateResult as K}from"./shared.js";import{buildCommentScript as k,NORM_COMMENT_DECORATION as w,normalizeCommentUrn as y}from"./social-api.js";const Q=1250;b({site:"linkedin",name:"reply",access:"write",description:"Reply to a comment on a LinkedIn post via the Voyager API. Dry-run by default; pass --send true to actually publish. The comment urn comes from `linkedin post-comments`.",domain:Z,strategy:q.COOKIE,browser:!0,args:[{name:"comment",type:"string",required:!0,positional:!0,help:"The comment to reply to: a comment_urn from `linkedin post-comments` (urn:li:comment:(activity:…,…) or urn:li:fsd_comment:(…))."},{name:"text",fromFile:!0,type:"string",required:!0,help:`Reply body (max ${Q} chars).`},{name:"send",type:"bool",required:!1,default:!1,help:"Actually post the reply. Default false = dry-run (validates the session only; nothing is posted)."}],columns:["status","parent_comment_urn","reply_urn","text_chars"],func:async(F,G)=>{if(!F)throw new Y("Browser session required for linkedin reply");const J=y(G?.comment),B=String(G?.text??"").replace(/ /g," ").trim();if(!B)throw new W("--text is required");if(B.length>Q)throw new W(`--text must be ${Q} characters or fewer (got ${B.length})`);const $=G?.send===!0||G?.send==="true",P=J.match(/urn:li:comment:\((activity|ugcPost):(\d+),/),V=P?`urn:li:${P[1]}:${P[2]}`:"";await F.goto(V?`https://www.linkedin.com/feed/update/${V}/`:"https://www.linkedin.com/feed/");await F.wait(2);if(!$){await z(F,"LinkedIn reply");return[{status:"dry_run",parent_comment_urn:J,reply_urn:"(not posted — pass --send true to publish)",text_chars:B.length}]}const f=K(await F.evaluate(k({threadUrn:J,text:B,decorationId:w})));if(!f?.ok){if(f?.stage==="auth"||f?.httpStatus===401||f?.httpStatus===403)throw new v(Z,`LinkedIn reply requires an active signed-in LinkedIn browser session (${f?.error||"auth"}).`);throw new Y(`LinkedIn reply failed: stage=${f?.stage||"unknown"} http=${f?.httpStatus||"?"} ${f?.error||""}`.trim())}return[{status:"replied",parent_comment_urn:J,reply_urn:f.commentUrn||"",text_chars:B.length}]}});
1
+ import{cli as d,Strategy as p}from"@jackwener/opencli/registry";import{ArgumentError as m,AuthRequiredError as h,CommandExecutionError as u}from"@jackwener/opencli/errors";import{assertLinkedInAuthenticated as y,LINKEDIN_DOMAIN as l,unwrapEvaluateResult as w}from"./shared.js";import{buildCommentScript as f,NORM_COMMENT_DECORATION as _,normalizeCommentUrn as g}from"./social-api.js";const i=1250;d({site:"linkedin",name:"reply",access:"write",description:"Reply to a comment on a LinkedIn post via the Voyager API. Dry-run by default; pass --send true to actually publish. The comment urn comes from `linkedin post-comments`.",domain:l,strategy:p.COOKIE,browser:!0,args:[{name:"comment",type:"string",required:!0,positional:!0,help:"The comment to reply to: a comment_urn from `linkedin post-comments` (urn:li:comment:(activity:…,…) or urn:li:fsd_comment:(…))."},{name:"text",fromFile:!0,type:"string",required:!0,help:`Reply body (max ${i} chars).`},{name:"send",type:"bool",required:!1,default:!1,help:"Actually post the reply. Default false = dry-run (validates the session only; nothing is posted)."}],columns:["status","parent_comment_urn","reply_urn","text_chars"],func:async(r,n)=>{if(!r)throw new u("Browser session required for linkedin reply");const o=g(n?.comment),e=String(n?.text??"").replace(/ /g," ").trim();if(!e)throw new m("--text is required");if(e.length>i)throw new m(`--text must be ${i} characters or fewer (got ${e.length})`);const c=n?.send===!0||n?.send==="true",s=o.match(/urn:li:comment:\((activity|ugcPost):(\d+),/),a=s?`urn:li:${s[1]}:${s[2]}`:"";await r.goto(a?`https://www.linkedin.com/feed/update/${a}/`:"https://www.linkedin.com/feed/");await r.wait(2);if(!c){await y(r,"LinkedIn reply");return[{status:"dry_run",parent_comment_urn:o,reply_urn:"(not posted — pass --send true to publish)",text_chars:e.length}]}const t=w(await r.evaluate(f({threadUrn:o,text:e,decorationId:_})));if(!t?.ok){if(t?.stage==="auth"||t?.httpStatus===401||t?.httpStatus===403)throw new h(l,`LinkedIn reply requires an active signed-in LinkedIn browser session (${t?.error||"auth"}).`);throw new u(`LinkedIn reply failed: stage=${t?.stage||"unknown"} http=${t?.httpStatus||"?"} ${t?.error||""}`.trim())}return[{status:"replied",parent_comment_urn:o,reply_urn:t.commentUrn||"",text_chars:e.length}]}});
@@ -1 +1 @@
1
- import{cli as $,Strategy as b}from"@jackwener/opencli/registry";import{ArgumentError as z,AuthRequiredError as P,CommandExecutionError as W}from"@jackwener/opencli/errors";import{assertLinkedInAuthenticated as Q,LINKEDIN_DOMAIN as Y,unwrapEvaluateResult as q}from"./shared.js";import{buildRepostScript as x,normalizeThreadUrn as K,REPOST_CREATE_QID as k}from"./social-api.js";const J=3000;$({site:"linkedin",name:"repost",access:"write",description:"Repost (reshare) a LinkedIn post to your own feed via the Voyager API. Plain repost by default; pass --text to quote-repost with your commentary. Dry-run unless --send true.",domain:Y,strategy:b.COOKIE,browser:!0,args:[{name:"post",type:"string",required:!0,positional:!0,help:"Post to repost: a LinkedIn post URL (…/feed/update/… or …/posts/…) or a raw urn:li:activity:… / urn:li:ugcPost:… urn."},{name:"text",fromFile:!0,type:"string",required:!1,help:`Optional commentary to quote-repost with (max ${J} chars). Omit for a plain repost.`},{name:"send",type:"bool",required:!1,default:!1,help:"Actually repost. Default false = dry-run (validates the session only; nothing is posted)."}],columns:["status","shared_urn","repost_urn","quote"],func:async(B,F)=>{if(!B)throw new W("Browser session required for linkedin repost");const V=K(F?.post),G=String(F?.text??"").replace(/ /g," ").trim();if(G.length>J)throw new z(`--text must be ${J} characters or fewer (got ${G.length})`);const Z=F?.send===!0||F?.send==="true";await B.goto("https://www.linkedin.com/feed/");await B.wait(2);if(!Z){await Q(B,"LinkedIn repost");return[{status:"dry_run",shared_urn:V,repost_urn:"(not posted — pass --send true to repost)",quote:G?"yes":""}]}const f=q(await B.evaluate(x({activityUrn:V,commentary:G,repostQid:k})));if(!f?.ok){if(f?.stage==="auth"||f?.httpStatus===401||f?.httpStatus===403)throw new P(Y,`LinkedIn repost requires an active signed-in LinkedIn browser session (${f?.error||"auth"}).`);throw new W(`LinkedIn repost failed: stage=${f?.stage||"unknown"} http=${f?.httpStatus||"?"} ${f?.error||""}`.trim())}return[{status:"reposted",shared_urn:f.shared_urn||"",repost_urn:f.repost_urn||"",quote:f.quote?"yes":""}]}});
1
+ import{cli as p,Strategy as d}from"@jackwener/opencli/registry";import{ArgumentError as l,AuthRequiredError as h,CommandExecutionError as i}from"@jackwener/opencli/errors";import{assertLinkedInAuthenticated as m,LINKEDIN_DOMAIN as a,unwrapEvaluateResult as c}from"./shared.js";import{buildRepostScript as w,normalizeThreadUrn as f,REPOST_CREATE_QID as y}from"./social-api.js";const o=3000;p({site:"linkedin",name:"repost",access:"write",description:"Repost (reshare) a LinkedIn post to your own feed via the Voyager API. Plain repost by default; pass --text to quote-repost with your commentary. Dry-run unless --send true.",domain:a,strategy:d.COOKIE,browser:!0,args:[{name:"post",type:"string",required:!0,positional:!0,help:"Post to repost: a LinkedIn post URL (…/feed/update/… or …/posts/…) or a raw urn:li:activity:… / urn:li:ugcPost:… urn."},{name:"text",fromFile:!0,type:"string",required:!1,help:`Optional commentary to quote-repost with (max ${o} chars). Omit for a plain repost.`},{name:"send",type:"bool",required:!1,default:!1,help:"Actually repost. Default false = dry-run (validates the session only; nothing is posted)."}],columns:["status","shared_urn","repost_urn","quote"],func:async(e,r)=>{if(!e)throw new i("Browser session required for linkedin repost");const n=f(r?.post),s=String(r?.text??"").replace(/ /g," ").trim();if(s.length>o)throw new l(`--text must be ${o} characters or fewer (got ${s.length})`);const u=r?.send===!0||r?.send==="true";await e.goto("https://www.linkedin.com/feed/");await e.wait(2);if(!u){await m(e,"LinkedIn repost");return[{status:"dry_run",shared_urn:n,repost_urn:"(not posted — pass --send true to repost)",quote:s?"yes":""}]}const t=c(await e.evaluate(w({activityUrn:n,commentary:s,repostQid:y})));if(!t?.ok){if(t?.stage==="auth"||t?.httpStatus===401||t?.httpStatus===403)throw new h(a,`LinkedIn repost requires an active signed-in LinkedIn browser session (${t?.error||"auth"}).`);throw new i(`LinkedIn repost failed: stage=${t?.stage||"unknown"} http=${t?.httpStatus||"?"} ${t?.error||""}`.trim())}return[{status:"reposted",shared_urn:t.shared_urn||"",repost_urn:t.repost_urn||"",quote:t.quote?"yes":""}]}});
@@ -1,4 +1,4 @@
1
- import{cli as U,Strategy as v}from"@jackwener/opencli/registry";import{ArgumentError as q,AuthRequiredError as f,CommandExecutionError as X}from"@jackwener/opencli/errors";import{createHash as N}from"node:crypto";const P="www.linkedin.com";function O(j){return String(j??"").replace(/[\u00a0\u202f]/g," ").replace(/\s+/g," ").trim()}function Y(j){if(j&&typeof j==="object"&&"data"in j&&"session"in j)return j.data;return j}function _(j){return O(j).replace(/\s*[•·]\s*(?:1st|2nd|3rd\+?|degree connection).*$/i,"").replace(/\s+LinkedIn.*$/i,"").toLowerCase()}function T(j){const G=String(j||"").toLowerCase();return G==="linkedin.com"||G.endsWith(".linkedin.com")}function B(j){const G=O(j);if(!G)return"";try{const D=new URL(G);if(D.protocol!=="https:"||D.username||D.password||D.port||!T(D.hostname))return"";const J=D.pathname.match(/^\/messaging\/thread\/([^/]+)\/?$/i);if(!J||!J[1])return"";D.hostname="www.linkedin.com";D.hash="";D.search="";if(!D.pathname.endsWith("/"))D.pathname+="/";return D.toString()}catch{return""}}function w(j){return N("sha256").update(O(j)).digest("hex")}function z(j,G){const D=O(j).toLowerCase(),J=O(G).toLowerCase();return!J||D.includes(J)}function C(j){return/\r|\n/.test(String(j??""))}function y(j,G){const D=_(G),J=(Array.isArray(j)?j:[]).map(O).filter(Boolean);return J.find((V)=>_(V)===D)||J[0]||""}function A(j,G){const D=O(G.expectedName),J=y(j?.headerNames,D),V=B(G.threadUrl),K=B(j?.url||""),Z=String(j?.bodyText||"");if(j?.authRequired)return{ok:!1,blockReason:"auth_required",expectedValue:D,actualValue:J,observedUrl:K};if(j?.searchFailure||/we didn't find anything|no results found|no results for/i.test(Z))return{ok:!1,blockReason:"search_failure_visible",expectedValue:D,actualValue:J,observedUrl:K};if(V&&K&&V!==K)return{ok:!1,blockReason:"thread_url_mismatch",expectedValue:V,actualValue:K,observedUrl:K};if(!J||_(J)!==_(D))return{ok:!1,blockReason:"recipient_header_mismatch",expectedValue:D,actualValue:J,observedUrl:K};if(!j?.composerFound)return{ok:!1,blockReason:"composer_not_found",expectedValue:D,actualValue:J,observedUrl:K};const Q=O(G.expectedLastHash);if(Q&&Q!==j?.latestMessageHash)return{ok:!1,blockReason:"latest_message_mismatch",expectedValue:Q,actualValue:j?.latestMessageHash||"",observedUrl:K};const W=O(G.expectedLastText);if(W&&!z(Z,W))return{ok:!1,blockReason:"latest_message_mismatch",expectedValue:W,actualValue:"",observedUrl:K};return{ok:!0,blockReason:"verified",expectedValue:D,actualValue:J,observedUrl:K}}function S(j,G,D=G){const J=O(j[G]);if(!J)throw new q(`${D} is required`);return J}function L(j,G,D=G){const J=String(j[G]??"");if(!O(J))throw new q(`${D} is required`);return J}function b(j,G){const D=B(j);if(!D)throw new q(`${G} must be an exact https://www.linkedin.com/messaging/thread/<id>/ URL`);return D}function h(){return String.raw`(() => {
1
+ import{cli as N,Strategy as A}from"@jackwener/opencli/registry";import{ArgumentError as b,AuthRequiredError as R,CommandExecutionError as c}from"@jackwener/opencli/errors";import{createHash as q}from"node:crypto";const v="www.linkedin.com";function o(e){return String(e??"").replace(/[\u00a0\u202f]/g," ").replace(/\s+/g," ").trim()}function d(e){if(e&&typeof e==="object"&&"data"in e&&"session"in e)return e.data;return e}function m(e){return o(e).replace(/\s*[•·]\s*(?:1st|2nd|3rd\+?|degree connection).*$/i,"").replace(/\s+LinkedIn.*$/i,"").toLowerCase()}function M(e){const n=String(e||"").toLowerCase();return n==="linkedin.com"||n.endsWith(".linkedin.com")}function p(e){const n=o(e);if(!n)return"";try{const t=new URL(n);if(t.protocol!=="https:"||t.username||t.password||t.port||!M(t.hostname))return"";const r=t.pathname.match(/^\/messaging\/thread\/([^/]+)\/?$/i);if(!r||!r[1])return"";t.hostname="www.linkedin.com";t.hash="";t.search="";if(!t.pathname.endsWith("/"))t.pathname+="/";return t.toString()}catch{return""}}function T(e){return q("sha256").update(o(e)).digest("hex")}function y(e,n){const t=o(e).toLowerCase(),r=o(n).toLowerCase();return!r||t.includes(r)}function L(e){return/\r|\n/.test(String(e??""))}function U(e,n){const t=m(n),r=(Array.isArray(e)?e:[]).map(o).filter(Boolean);return r.find((i)=>m(i)===t)||r[0]||""}function x(e,n){const t=o(n.expectedName),r=U(e?.headerNames,t),i=p(n.threadUrl),a=p(e?.url||""),u=String(e?.bodyText||"");if(e?.authRequired)return{ok:!1,blockReason:"auth_required",expectedValue:t,actualValue:r,observedUrl:a};if(e?.searchFailure||/we didn't find anything|no results found|no results for/i.test(u))return{ok:!1,blockReason:"search_failure_visible",expectedValue:t,actualValue:r,observedUrl:a};if(i&&a&&i!==a)return{ok:!1,blockReason:"thread_url_mismatch",expectedValue:i,actualValue:a,observedUrl:a};if(!r||m(r)!==m(t))return{ok:!1,blockReason:"recipient_header_mismatch",expectedValue:t,actualValue:r,observedUrl:a};if(!e?.composerFound)return{ok:!1,blockReason:"composer_not_found",expectedValue:t,actualValue:r,observedUrl:a};const s=o(n.expectedLastHash);if(s&&s!==e?.latestMessageHash)return{ok:!1,blockReason:"latest_message_mismatch",expectedValue:s,actualValue:e?.latestMessageHash||"",observedUrl:a};const l=o(n.expectedLastText);if(l&&!y(u,l))return{ok:!1,blockReason:"latest_message_mismatch",expectedValue:l,actualValue:"",observedUrl:a};return{ok:!0,blockReason:"verified",expectedValue:t,actualValue:r,observedUrl:a}}function C(e,n,t=n){const r=o(e[n]);if(!r)throw new b(`${t} is required`);return r}function S(e,n,t=n){const r=String(e[n]??"");if(!o(r))throw new b(`${t} is required`);return r}function V(e,n){const t=p(e);if(!t)throw new b(`${n} must be an exact https://www.linkedin.com/messaging/thread/<id>/ URL`);return t}function B(){return String.raw`(() => {
2
2
  const marker = '__OPENCLI_LINKEDIN_PROBE__';
3
3
  void marker;
4
4
  const clean = (s) => String(s || '').replace(/[\u00a0\u202f]/g, ' ').replace(/\s+/g, ' ').trim();
@@ -53,7 +53,7 @@ import{cli as U,Strategy as v}from"@jackwener/opencli/registry";import{ArgumentE
53
53
  latestMessageText: lastMeaningfulLine,
54
54
  latestMessageHash: '',
55
55
  };
56
- })()`}function x(){return String.raw`(() => {
56
+ })()`}function P(){return String.raw`(() => {
57
57
  const marker = '__OPENCLI_LINKEDIN_FOCUS_COMPOSER__';
58
58
  void marker;
59
59
  const clean = (s) => String(s || '').replace(/[\u00a0\u202f]/g, ' ').replace(/\s+/g, ' ').trim();
@@ -64,17 +64,17 @@ import{cli as U,Strategy as v}from"@jackwener/opencli/registry";import{ArgumentE
64
64
  composer.innerHTML = '';
65
65
  composer.dispatchEvent(new InputEvent('input', { bubbles: true, inputType: 'deleteContentBackward', data: null }));
66
66
  return { ok: true, composerText: clean(composer.innerText || composer.textContent) };
67
- })()`}function i(){return String.raw`(() => {
67
+ })()`}function D(){return String.raw`(() => {
68
68
  const marker = '__OPENCLI_LINKEDIN_READ_COMPOSER__';
69
69
  void marker;
70
70
  const clean = (s) => String(s || '').replace(/[\u00a0\u202f]/g, ' ').replace(/\s+/g, ' ').trim();
71
71
  const composer = Array.from(document.querySelectorAll('[contenteditable="true"][role="textbox"], div.msg-form__contenteditable[contenteditable="true"], [aria-label*="Write a message" i]'))
72
72
  .find((el) => !el.closest('[aria-hidden="true"]') && el.offsetParent !== null);
73
73
  return { ok: Boolean(composer), composerText: composer ? clean(composer.innerText || composer.textContent) : '' };
74
- })()`}function k(j){return`(() => {
74
+ })()`}function I(e){return`(() => {
75
75
  const marker = '__OPENCLI_LINKEDIN_FILL_COMPOSER_MULTILINE__';
76
76
  void marker;
77
- const message = ${JSON.stringify(String(j??""))};
77
+ const message = ${JSON.stringify(String(e??""))};
78
78
  const normalize = (s) => String(s || '').replace(/[\\u00a0\\u202f]/g, ' ').replace(/\\s+/g, ' ').trim();
79
79
  const composer = Array.from(document.querySelectorAll('[contenteditable="true"][role="textbox"], div.msg-form__contenteditable[contenteditable="true"], [aria-label*="Write a message" i]'))
80
80
  .find((el) => !el.closest('[aria-hidden="true"]') && el.offsetParent !== null);
@@ -139,7 +139,7 @@ import{cli as U,Strategy as v}from"@jackwener/opencli/registry";import{ArgumentE
139
139
  method,
140
140
  renderedBreaks: brCount + childBlockCount,
141
141
  };
142
- })()`}function n(){return String.raw`(() => {
142
+ })()`}function O(){return String.raw`(() => {
143
143
  const marker = '__OPENCLI_LINKEDIN_CLICK_SEND__';
144
144
  void marker;
145
145
  const buttons = Array.from(document.querySelectorAll('button'));
@@ -151,5 +151,5 @@ import{cli as U,Strategy as v}from"@jackwener/opencli/registry";import{ArgumentE
151
151
  if (send.disabled || send.getAttribute('aria-disabled') === 'true') return { ok: false, error: 'send_button_disabled', sent: false };
152
152
  send.click();
153
153
  return { ok: true, sent: true };
154
- })()`}async function F(j){const G=Y(await j.evaluate(h())),D=O(G?.latestMessageText||"");return{...G||{},latestMessageText:D,latestMessageHash:D?w(D):""}}async function m(j,G){if(!C(G)){await j.insertText(G);return{method:"insert_text",renderedBreaks:0}}const D=Y(await j.evaluate(k(G)));if(D?.ok)return{method:D.method||"dom_multiline",renderedBreaks:Number(D.renderedBreaks||0)};await j.insertText(G);return{method:"insert_text_fallback",renderedBreaks:0}}U({site:"linkedin",name:"safe-send",access:"write",description:"Fail-closed LinkedIn message sender that verifies exact thread, recipient, and latest message before filling/sending",domain:P,strategy:v.UI,browser:!0,args:[{name:"thread-url",required:!0,help:"Exact LinkedIn messaging thread URL to open and verify"},{name:"expected-name",required:!0,help:"Expected visible recipient name in the active thread header"},{name:"message",fromFile:!0,required:!0,help:"Message body to send or dry-run"},{name:"expected-last-text",help:"Substring expected in the currently visible latest conversation context"},{name:"expected-last-hash",help:"SHA-256 hash of expected latest visible message text"},{name:"send",type:"bool",default:!1,help:"Actually click Send. Default is dry-run verification only."},{name:"screenshot",type:"bool",default:!1,help:"Capture a screenshot during verification"}],columns:["status","recipient","reason","thread_url","message_chars","screenshot"],func:async(j,G)=>{if(!j)throw new X("Browser session required for linkedin safe-send");const D=b(S(G,"thread-url","--thread-url"),"--thread-url"),J=S(G,"expected-name","--expected-name"),V=L(G,"message","--message");await j.goto("https://www.linkedin.com/messaging/");await j.wait(4);await j.goto(D);await j.wait(12);let K=await F(j);const Z=O(G["expected-last-text"]);for(let $=0;Z&&$<6&&!z(K.bodyText,Z);$+=1){await j.wait(2);K=await F(j)}const Q=A(K,{expectedName:J,threadUrl:D,expectedLastText:G["expected-last-text"],expectedLastHash:G["expected-last-hash"]});if(Q.blockReason==="auth_required")throw new f(P,"LinkedIn safe-send requires an active signed-in LinkedIn browser session.");if(!Q.ok){const $=[`Expected ${Q.expectedValue}; actual ${Q.actualValue||"not_visible"} at ${Q.observedUrl||"url_not_available"}`,`Observed headers: ${(K.headerNames||[]).join(" | ")||"no_visible_headers"}`,`Title: ${K.title||"title_not_available"}`,`Body: ${O(K.bodyText||"").slice(0,500)}`].join(`
155
- `);throw new X(`LinkedIn safe-send blocked: ${Q.blockReason}`,$)}let W="";if(G.screenshot&&typeof j.screenshot==="function")W=await j.screenshot({fullPage:!1});if(!G.send)return[{status:"verified_dry_run",recipient:Q.actualValue,reason:Q.blockReason,thread_url:Q.observedUrl,message_chars:V.length,screenshot:W?"captured":""}];const H=Y(await j.evaluate(x()));if(!H?.ok)throw new X(`LinkedIn safe-send blocked: ${H?.error||"composer_focus_failed"}`);await m(j,V);await j.wait(0.6+Math.random()*0.8);const I=Y(await j.evaluate(i()));if(!I?.ok||O(I.composerText)!==O(V))throw new X("LinkedIn safe-send blocked: composer_text_mismatch",`Composer text did not exactly match intended message for ${J}.`);const E=await F(j),R=A(E,{expectedName:J,threadUrl:D,expectedLastText:G["expected-last-text"],expectedLastHash:G["expected-last-hash"]});if(!R.ok)throw new X(`LinkedIn safe-send blocked after fill: ${R.blockReason}`);const M=Y(await j.evaluate(n()));if(!M?.ok||!M.sent)throw new X(`LinkedIn safe-send blocked: ${M?.error||"send_click_failed"}`);await j.wait(0.8+Math.random()*1.2);return[{status:"sent",recipient:Q.actualValue,reason:Q.blockReason,thread_url:Q.observedUrl,message_chars:V.length,screenshot:W?"captured":""}]}});export const __test__={normalizeWhitespace:O,unwrapEvaluateResult:Y,normalizeName:_,canonicalizeLinkedInThreadUrl:B,hashText:w,hasLineBreaks:C,requireRawStringArg:L,buildFillComposerMultilineScript:k,assessThreadSafety:A};
154
+ })()`}async function _(e){const n=d(await e.evaluate(B())),t=o(n?.latestMessageText||"");return{...n||{},latestMessageText:t,latestMessageHash:t?T(t):""}}async function F(e,n){if(!L(n)){await e.insertText(n);return{method:"insert_text",renderedBreaks:0}}const t=d(await e.evaluate(I(n)));if(t?.ok)return{method:t.method||"dom_multiline",renderedBreaks:Number(t.renderedBreaks||0)};await e.insertText(n);return{method:"insert_text_fallback",renderedBreaks:0}}N({site:"linkedin",name:"safe-send",access:"write",description:"Fail-closed LinkedIn message sender that verifies exact thread, recipient, and latest message before filling/sending",domain:v,strategy:A.UI,browser:!0,args:[{name:"thread-url",required:!0,help:"Exact LinkedIn messaging thread URL to open and verify"},{name:"expected-name",required:!0,help:"Expected visible recipient name in the active thread header"},{name:"message",fromFile:!0,required:!0,help:"Message body to send or dry-run"},{name:"expected-last-text",help:"Substring expected in the currently visible latest conversation context"},{name:"expected-last-hash",help:"SHA-256 hash of expected latest visible message text"},{name:"send",type:"bool",default:!1,help:"Actually click Send. Default is dry-run verification only."},{name:"screenshot",type:"bool",default:!1,help:"Capture a screenshot during verification"}],columns:["status","recipient","reason","thread_url","message_chars","screenshot"],func:async(e,n)=>{if(!e)throw new c("Browser session required for linkedin safe-send");const t=V(C(n,"thread-url","--thread-url"),"--thread-url"),r=C(n,"expected-name","--expected-name"),i=S(n,"message","--message");await e.goto("https://www.linkedin.com/messaging/");await e.wait(4);await e.goto(t);await e.wait(12);let a=await _(e);const u=o(n["expected-last-text"]);for(let f=0;u&&f<6&&!y(a.bodyText,u);f+=1){await e.wait(2);a=await _(e)}const s=x(a,{expectedName:r,threadUrl:t,expectedLastText:n["expected-last-text"],expectedLastHash:n["expected-last-hash"]});if(s.blockReason==="auth_required")throw new R(v,"LinkedIn safe-send requires an active signed-in LinkedIn browser session.");if(!s.ok){const f=[`Expected ${s.expectedValue}; actual ${s.actualValue||"not_visible"} at ${s.observedUrl||"url_not_available"}`,`Observed headers: ${(a.headerNames||[]).join(" | ")||"no_visible_headers"}`,`Title: ${a.title||"title_not_available"}`,`Body: ${o(a.bodyText||"").slice(0,500)}`].join(`
155
+ `);throw new c(`LinkedIn safe-send blocked: ${s.blockReason}`,f)}let l="";if(n.screenshot&&typeof e.screenshot==="function")l=await e.screenshot({fullPage:!1});if(!n.send)return[{status:"verified_dry_run",recipient:s.actualValue,reason:s.blockReason,thread_url:s.observedUrl,message_chars:i.length,screenshot:l?"captured":""}];const g=d(await e.evaluate(P()));if(!g?.ok)throw new c(`LinkedIn safe-send blocked: ${g?.error||"composer_focus_failed"}`);await F(e,i);await e.wait(0.6+Math.random()*0.8);const w=d(await e.evaluate(D()));if(!w?.ok||o(w.composerText)!==o(i))throw new c("LinkedIn safe-send blocked: composer_text_mismatch",`Composer text did not exactly match intended message for ${r}.`);const E=await _(e),k=x(E,{expectedName:r,threadUrl:t,expectedLastText:n["expected-last-text"],expectedLastHash:n["expected-last-hash"]});if(!k.ok)throw new c(`LinkedIn safe-send blocked after fill: ${k.blockReason}`);const h=d(await e.evaluate(O()));if(!h?.ok||!h.sent)throw new c(`LinkedIn safe-send blocked: ${h?.error||"send_click_failed"}`);await e.wait(0.8+Math.random()*1.2);return[{status:"sent",recipient:s.actualValue,reason:s.blockReason,thread_url:s.observedUrl,message_chars:i.length,screenshot:l?"captured":""}]}});export const __test__={normalizeWhitespace:o,unwrapEvaluateResult:d,normalizeName:m,canonicalizeLinkedInThreadUrl:p,hashText:T,hasLineBreaks:L,requireRawStringArg:S,buildFillComposerMultilineScript:I,assessThreadSafety:x};
@@ -1,9 +1,9 @@
1
- import{cli as y,Strategy as M}from"@jackwener/opencli/registry";import{ArgumentError as P,AuthRequiredError as z,CommandExecutionError as V,EmptyResultError as _}from"@jackwener/opencli/errors";const b="www.linkedin.com",L="https://www.linkedin.com/sales/inbox/",THREADS_BASE="https://www.linkedin.com/sales-api/salesApiMessagingThreads",O=20,F=40,W=500,THREAD_DECORATION="(id,restrictions,archived,unreadMessageCount,nextPageStartsAt,totalMessageCount,messages*(id,type,contentFlag,deliveredAt,lastEditedAt,subject,body,footerText,blockCopy,attachments,author,systemMessageContent),participants*~fs_salesProfile(entityUrn,firstName,lastName,fullName,degree,profilePictureDisplayImage,objectUrn,inmailRestriction))";export function normalizeWhitespace(Q){return String(Q??"").replace(/[\u00a0\u202f]/g," ").replace(/\s+/g," ").trim()}export function parseLimit(Q,Y=F){if(Q===void 0||Q===null||Q==="")return Y;const $=Number(Q);if(!Number.isInteger($)||$<1||$>W)throw new P(`--limit must be an integer between 1 and ${W}`);return $}function D(Q){if(Q&&typeof Q==="object"&&"data"in Q&&"session"in Q)return Q.data;return Q}export function encodeRestliDecoration(Q){return encodeURIComponent(Q).replace(/\(/g,"%28").replace(/\)/g,"%29")}function C(Q){return Q?`https://www.linkedin.com/sales/inbox/${encodeURIComponent(Q)}`:""}function j({count:Q=O,pageStartsAt:Y=""}={}){let $=`${THREADS_BASE}?decoration=${encodeRestliDecoration(THREAD_DECORATION)}&count=${Q}&filter=INBOX&q=filter`;if(Y)$+=`&pageStartsAt=${encodeURIComponent(Y)}`;return $}function N(Q){const Y=Q?.participantsResolutionResults||{};return(Array.isArray(Q?.participants)?Q.participants:Object.keys(Y)).map((q)=>Y[q]||{entityUrn:q}).filter(Boolean)}function v(Q){return String(Q?.degree??"").trim()==="0"}function R(Q){const Y=N(Q),$=Y.find((q)=>!v(q))||Y[0];return normalizeWhitespace($?.fullName||[$?.firstName,$?.lastName].filter(Boolean).join(" "))}function f(Q){if(!Q||typeof Q!=="object"||!Array.isArray(Q.elements))throw new V("Sales Navigator messaging threads API returned malformed payload");return Q.elements.map((Y)=>{if(!Y||typeof Y!=="object")throw new V("Sales Navigator messaging threads API returned malformed thread row");const $=Array.isArray(Y?.messages)?Y.messages:[],q=$[0]||{},k=Number(q.deliveredAt||Y?.nextPageStartsAt||0),J=normalizeWhitespace(Y?.id||"");if(!J)throw new V("Sales Navigator messaging thread row missing id");return{thread_id:J,thread_url:C(J),person_name:R(Y),last_message_snippet:normalizeWhitespace(q.body||q.subject||"").slice(0,300),last_activity_time:k?new Date(k).toISOString():"",unread:Number(Y?.unreadMessageCount||0)>0,unread_count:Number(Y?.unreadMessageCount||0),total_message_count:Number(Y?.totalMessageCount||$.length||0),archived:Boolean(Y?.archived),next_page_starts_at:normalizeWhitespace(Y?.nextPageStartsAt||""),participants:N(Y).map((G)=>({name:normalizeWhitespace(G.fullName||[G.firstName,G.lastName].filter(Boolean).join(" ")),entity_urn:normalizeWhitespace(G.entityUrn||""),object_urn:normalizeWhitespace(G.objectUrn||""),degree:normalizeWhitespace(G.degree??"")}))}})}function S(Q,Y){return String.raw`(async () => {
1
+ import{cli as b,Strategy as A}from"@jackwener/opencli/registry";import{ArgumentError as I,AuthRequiredError as w,CommandExecutionError as o,EmptyResultError as v}from"@jackwener/opencli/errors";const m="www.linkedin.com",k="https://www.linkedin.com/sales/inbox/",THREADS_BASE="https://www.linkedin.com/sales-api/salesApiMessagingThreads",h=20,g=40,_=500,THREAD_DECORATION="(id,restrictions,archived,unreadMessageCount,nextPageStartsAt,totalMessageCount,messages*(id,type,contentFlag,deliveredAt,lastEditedAt,subject,body,footerText,blockCopy,attachments,author,systemMessageContent),participants*~fs_salesProfile(entityUrn,firstName,lastName,fullName,degree,profilePictureDisplayImage,objectUrn,inmailRestriction))";export function normalizeWhitespace(e){return String(e??"").replace(/[\u00a0\u202f]/g," ").replace(/\s+/g," ").trim()}export function parseLimit(e,t=g){if(e===void 0||e===null||e==="")return t;const n=Number(e);if(!Number.isInteger(n)||n<1||n>_)throw new I(`--limit must be an integer between 1 and ${_}`);return n}function j(e){if(e&&typeof e==="object"&&"data"in e&&"session"in e)return e.data;return e}export function encodeRestliDecoration(e){return encodeURIComponent(e).replace(/\(/g,"%28").replace(/\)/g,"%29")}function S(e){return e?`https://www.linkedin.com/sales/inbox/${encodeURIComponent(e)}`:""}function y({count:e=h,pageStartsAt:t=""}={}){let n=`${THREADS_BASE}?decoration=${encodeRestliDecoration(THREAD_DECORATION)}&count=${e}&filter=INBOX&q=filter`;if(t)n+=`&pageStartsAt=${encodeURIComponent(t)}`;return n}function N(e){const t=e?.participantsResolutionResults||{};return(Array.isArray(e?.participants)?e.participants:Object.keys(t)).map((r)=>t[r]||{entityUrn:r}).filter(Boolean)}function E(e){return String(e?.degree??"").trim()==="0"}function P(e){const t=N(e),n=t.find((r)=>!E(r))||t[0];return normalizeWhitespace(n?.fullName||[n?.firstName,n?.lastName].filter(Boolean).join(" "))}function x(e){if(!e||typeof e!=="object"||!Array.isArray(e.elements))throw new o("Sales Navigator messaging threads API returned malformed payload");return e.elements.map((t)=>{if(!t||typeof t!=="object")throw new o("Sales Navigator messaging threads API returned malformed thread row");const n=Array.isArray(t?.messages)?t.messages:[],r=n[0]||{},s=Number(r.deliveredAt||t?.nextPageStartsAt||0),i=normalizeWhitespace(t?.id||"");if(!i)throw new o("Sales Navigator messaging thread row missing id");return{thread_id:i,thread_url:S(i),person_name:P(t),last_message_snippet:normalizeWhitespace(r.body||r.subject||"").slice(0,300),last_activity_time:s?new Date(s).toISOString():"",unread:Number(t?.unreadMessageCount||0)>0,unread_count:Number(t?.unreadMessageCount||0),total_message_count:Number(t?.totalMessageCount||n.length||0),archived:Boolean(t?.archived),next_page_starts_at:normalizeWhitespace(t?.nextPageStartsAt||""),participants:N(t).map((a)=>({name:normalizeWhitespace(a.fullName||[a.firstName,a.lastName].filter(Boolean).join(" ")),entity_urn:normalizeWhitespace(a.entityUrn||""),object_urn:normalizeWhitespace(a.objectUrn||""),degree:normalizeWhitespace(a.degree??"")}))}})}function R(e,t){return String.raw`(async () => {
2
2
  try {
3
- const res = await fetch(${JSON.stringify(Q)}, {
3
+ const res = await fetch(${JSON.stringify(e)}, {
4
4
  credentials: 'include',
5
5
  headers: {
6
- 'csrf-token': ${JSON.stringify(Y)},
6
+ 'csrf-token': ${JSON.stringify(t)},
7
7
  'x-restli-protocol-version': '2.0.0',
8
8
  accept: 'application/json',
9
9
  },
@@ -17,5 +17,5 @@ import{cli as y,Strategy as M}from"@jackwener/opencli/registry";import{ArgumentE
17
17
  } catch (e) {
18
18
  return { error: 'fetch failed: ' + ((e && e.message) || String(e)) };
19
19
  }
20
- })()`}export async function getCsrf(Q){const $=(await Q.getCookies({url:"https://www.linkedin.com"})).find((q)=>q.name==="JSESSIONID")?.value;if(!$)throw new z(b,"LinkedIn JSESSIONID cookie not found. Please sign in to LinkedIn.");return $.replace(/^\"|\"$/g,"")}export async function fetchSalesnavJson(Q,Y,$,q){const k=D(await Q.evaluate(S($,Y)));if(k?.authRequired)throw new z(b,`${q} authentication failed (HTTP ${k.status||"auth_required"}).`);if(k?.error||!k?.json)throw new V(`${q} returned an unexpected response`,`${k?.error||"no_json"}
21
- ${normalizeWhitespace(k?.text||"").slice(0,500)}`);return k.json}export async function fetchInboxRows(Q,{limit:Y=F,maxPages:$=30}={}){const q=await getCsrf(Q),k=[],J=new Set;let G="",X=0,U=!1;while(k.length<Y&&X<$){const K=await fetchSalesnavJson(Q,q,j({count:O,pageStartsAt:G}),"Sales Navigator messaging threads API");X+=1;const Z=f(K);if(Z.length===0)break;for(const H of Z){if(J.has(H.thread_id))continue;J.add(H.thread_id);k.push(H);if(k.length>=Y)break}const B=Z[Z.length-1]?.next_page_starts_at;U=Boolean(B);if(!B)break;if(B===G)throw new V("Sales Navigator messaging threads API returned the same cursor twice");G=B}if(k.length<Y&&U&&X>=$)throw new V(`Sales Navigator messaging threads API reached the ${$}-page safety cap before collecting ${Y} conversations`);return k.slice(0,Y).map((K,Z)=>({...K,rank:Z+1}))}export{THREAD_DECORATION,THREADS_BASE};y({site:"linkedin",name:"salesnav-inbox",access:"read",description:"List LinkedIn Sales Navigator message conversations with API pagination",domain:b,strategy:M.UI,browser:!0,args:[{name:"limit",type:"number",default:F,help:"Maximum conversations to return (1-500)"},{name:"max-pages",type:"number",default:30,help:"Maximum Sales Navigator API pages to fetch"},{name:"unread-only",type:"bool",default:!1,help:"Return only unread conversations"}],columns:["rank","thread_id","thread_url","person_name","last_message_snippet","last_activity_time","unread","unread_count","total_message_count","archived","participants","next_page_starts_at"],func:async(Q,Y)=>{if(!Q)throw new V("Browser session required for linkedin salesnav-inbox");const $=parseLimit(Y.limit),q=parseLimit(Y["max-pages"],30);await Q.goto(L);await Q.wait(4);let k=await fetchInboxRows(Q,{limit:$,maxPages:q});if(Y["unread-only"])k=k.filter((J)=>J.unread);if(k.length===0){if(Y["unread-only"])return[];throw new _("linkedin salesnav-inbox","No Sales Navigator conversations were found.")}return k.slice(0,$).map((J,G)=>({...J,rank:G+1}))}});export const __test__={THREAD_DECORATION,normalizeWhitespace,parseLimit,encodeRestliDecoration,salesnavThreadUrl:C,threadListUrl:j,parseSalesnavThreads:f,fetchInboxRows};
20
+ })()`}export async function getCsrf(e){const n=(await e.getCookies({url:"https://www.linkedin.com"})).find((r)=>r.name==="JSESSIONID")?.value;if(!n)throw new w(m,"LinkedIn JSESSIONID cookie not found. Please sign in to LinkedIn.");return n.replace(/^\"|\"$/g,"")}export async function fetchSalesnavJson(e,t,n,r){const s=j(await e.evaluate(R(n,t)));if(s?.authRequired)throw new w(m,`${r} authentication failed (HTTP ${s.status||"auth_required"}).`);if(s?.error||!s?.json)throw new o(`${r} returned an unexpected response`,`${s?.error||"no_json"}
21
+ ${normalizeWhitespace(s?.text||"").slice(0,500)}`);return s.json}export async function fetchInboxRows(e,{limit:t=g,maxPages:n=30}={}){const r=await getCsrf(e),s=[],i=new Set;let a="",u=0,p=!1;while(s.length<t&&u<n){const d=await fetchSalesnavJson(e,r,y({count:h,pageStartsAt:a}),"Sales Navigator messaging threads API");u+=1;const c=x(d);if(c.length===0)break;for(const f of c){if(i.has(f.thread_id))continue;i.add(f.thread_id);s.push(f);if(s.length>=t)break}const l=c[c.length-1]?.next_page_starts_at;p=Boolean(l);if(!l)break;if(l===a)throw new o("Sales Navigator messaging threads API returned the same cursor twice");a=l}if(s.length<t&&p&&u>=n)throw new o(`Sales Navigator messaging threads API reached the ${n}-page safety cap before collecting ${t} conversations`);return s.slice(0,t).map((d,c)=>({...d,rank:c+1}))}export{THREAD_DECORATION,THREADS_BASE};b({site:"linkedin",name:"salesnav-inbox",access:"read",description:"List LinkedIn Sales Navigator message conversations with API pagination",domain:m,strategy:A.UI,browser:!0,args:[{name:"limit",type:"number",default:g,help:"Maximum conversations to return (1-500)"},{name:"max-pages",type:"number",default:30,help:"Maximum Sales Navigator API pages to fetch"},{name:"unread-only",type:"bool",default:!1,help:"Return only unread conversations"}],columns:["rank","thread_id","thread_url","person_name","last_message_snippet","last_activity_time","unread","unread_count","total_message_count","archived","participants","next_page_starts_at"],func:async(e,t)=>{if(!e)throw new o("Browser session required for linkedin salesnav-inbox");const n=parseLimit(t.limit),r=parseLimit(t["max-pages"],30);await e.goto(k);await e.wait(4);let s=await fetchInboxRows(e,{limit:n,maxPages:r});if(t["unread-only"])s=s.filter((i)=>i.unread);if(s.length===0){if(t["unread-only"])return[];throw new v("linkedin salesnav-inbox","No Sales Navigator conversations were found.")}return s.slice(0,n).map((i,a)=>({...i,rank:a+1}))}});export const __test__={THREAD_DECORATION,normalizeWhitespace,parseLimit,encodeRestliDecoration,salesnavThreadUrl:S,threadListUrl:y,parseSalesnavThreads:x,fetchInboxRows};