@jackwener/opencli 1.1.1 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/build-extension.yml +3 -3
- package/.github/workflows/ci.yml +6 -6
- package/.github/workflows/doc-check.yml +3 -3
- package/.github/workflows/e2e-headed.yml +2 -2
- package/.github/workflows/pkg-pr-new.yml +2 -2
- package/.github/workflows/release.yml +3 -3
- package/.github/workflows/security.yml +2 -2
- package/CONTRIBUTING.md +39 -1
- package/README.md +13 -10
- package/README.zh-CN.md +43 -17
- package/SKILL.md +10 -5
- package/dist/browser/cdp.d.ts +4 -4
- package/dist/browser/cdp.js +39 -16
- package/dist/browser/daemon-client.d.ts +4 -2
- package/dist/browser/daemon-client.js +17 -4
- package/dist/browser/dom-helpers.js +38 -7
- package/dist/browser/dom-snapshot.d.ts +86 -0
- package/dist/browser/dom-snapshot.js +729 -0
- package/dist/browser/dom-snapshot.test.d.ts +11 -0
- package/dist/browser/dom-snapshot.test.js +212 -0
- package/dist/browser/index.d.ts +2 -0
- package/dist/browser/index.js +1 -0
- package/dist/browser/mcp.js +3 -1
- package/dist/browser/page.d.ts +14 -24
- package/dist/browser/page.js +46 -6
- package/dist/build-manifest.d.ts +11 -4
- package/dist/build-manifest.js +59 -21
- package/dist/build-manifest.test.js +58 -2
- package/dist/cli-manifest.json +3856 -1509
- package/dist/cli.js +66 -0
- package/dist/clis/barchart/greeks.js +1 -1
- package/dist/clis/barchart/options.js +1 -1
- package/dist/clis/barchart/quote.js +1 -1
- package/dist/clis/bilibili/download.js +1 -1
- package/dist/clis/bilibili/following.js +1 -1
- package/dist/clis/bilibili/subtitle.js +1 -1
- package/dist/clis/bilibili/user-videos.js +1 -1
- package/dist/clis/boss/batchgreet.js +10 -97
- package/dist/clis/boss/chatlist.js +8 -25
- package/dist/clis/boss/chatmsg.js +11 -42
- package/dist/clis/boss/common.d.ts +92 -0
- package/dist/clis/boss/common.js +223 -0
- package/dist/clis/boss/detail.js +7 -49
- package/dist/clis/boss/exchange.js +13 -79
- package/dist/clis/boss/greet.js +18 -145
- package/dist/clis/boss/invite.js +26 -121
- package/dist/clis/boss/joblist.js +6 -31
- package/dist/clis/boss/mark.js +12 -85
- package/dist/clis/boss/recommend.js +10 -49
- package/dist/clis/boss/resume.js +18 -118
- package/dist/clis/boss/search.js +12 -60
- package/dist/clis/boss/send.js +17 -151
- package/dist/clis/boss/stats.js +18 -69
- package/dist/clis/coupang/add-to-cart.js +1 -1
- package/dist/clis/devto/tag.yaml +34 -0
- package/dist/clis/devto/top.yaml +29 -0
- package/dist/clis/devto/user.yaml +33 -0
- package/dist/clis/douban/book-hot.d.ts +1 -0
- package/dist/clis/douban/book-hot.js +14 -0
- package/dist/clis/douban/marks.d.ts +1 -0
- package/dist/clis/douban/marks.js +115 -0
- package/dist/clis/douban/movie-hot.d.ts +1 -0
- package/dist/clis/douban/movie-hot.js +14 -0
- package/dist/clis/douban/reviews.d.ts +1 -0
- package/dist/clis/douban/reviews.js +106 -0
- package/dist/clis/douban/search.d.ts +1 -0
- package/dist/clis/douban/search.js +16 -0
- package/dist/clis/douban/shared.d.ts +4 -0
- package/dist/clis/douban/shared.js +155 -0
- package/dist/clis/douban/subject.yaml +76 -0
- package/dist/clis/douban/top250.yaml +70 -0
- package/dist/clis/douban/utils.d.ts +35 -0
- package/dist/clis/douban/utils.js +48 -0
- package/dist/clis/facebook/add-friend.yaml +43 -0
- package/dist/clis/facebook/events.yaml +44 -0
- package/dist/clis/facebook/feed.yaml +63 -0
- package/dist/clis/facebook/friends.yaml +42 -0
- package/dist/clis/facebook/groups.yaml +50 -0
- package/dist/clis/facebook/join-group.yaml +44 -0
- package/dist/clis/facebook/memories.yaml +39 -0
- package/dist/clis/facebook/notifications.yaml +40 -0
- package/dist/clis/facebook/profile.yaml +37 -0
- package/dist/clis/facebook/search.yaml +46 -0
- package/dist/clis/google/news.d.ts +5 -0
- package/dist/clis/google/news.js +58 -0
- package/dist/clis/google/search.d.ts +10 -0
- package/dist/clis/google/search.js +127 -0
- package/dist/clis/google/suggest.d.ts +5 -0
- package/dist/clis/google/suggest.js +34 -0
- package/dist/clis/google/trends.d.ts +5 -0
- package/dist/clis/google/trends.js +38 -0
- package/dist/clis/google/utils.d.ts +9 -0
- package/dist/clis/google/utils.js +23 -0
- package/dist/clis/google/utils.test.d.ts +1 -0
- package/dist/clis/google/utils.test.js +75 -0
- package/dist/clis/grok/ask.d.ts +14 -0
- package/dist/clis/grok/ask.js +257 -65
- package/dist/clis/grok/ask.test.d.ts +1 -0
- package/dist/clis/grok/ask.test.js +36 -0
- package/dist/clis/instagram/comment.yaml +52 -0
- package/dist/clis/instagram/explore.yaml +43 -0
- package/dist/clis/instagram/follow.yaml +41 -0
- package/dist/clis/instagram/followers.yaml +51 -0
- package/dist/clis/instagram/following.yaml +51 -0
- package/dist/clis/instagram/like.yaml +46 -0
- package/dist/clis/instagram/profile.yaml +42 -0
- package/dist/clis/instagram/save.yaml +46 -0
- package/dist/clis/instagram/saved.yaml +40 -0
- package/dist/clis/instagram/search.yaml +43 -0
- package/dist/clis/instagram/unfollow.yaml +38 -0
- package/dist/clis/instagram/unlike.yaml +46 -0
- package/dist/clis/instagram/unsave.yaml +46 -0
- package/dist/clis/instagram/user.yaml +54 -0
- package/dist/clis/jike/repost.js +1 -1
- package/dist/clis/jimeng/generate.yaml +1 -0
- package/dist/clis/linux-do/category.yaml +1 -0
- package/dist/clis/lobsters/active.yaml +29 -0
- package/dist/clis/lobsters/hot.yaml +29 -0
- package/dist/clis/lobsters/newest.yaml +29 -0
- package/dist/clis/lobsters/tag.yaml +34 -0
- package/dist/clis/medium/feed.d.ts +1 -0
- package/dist/clis/medium/feed.js +15 -0
- package/dist/clis/medium/search.d.ts +1 -0
- package/dist/clis/medium/search.js +15 -0
- package/dist/clis/medium/shared.d.ts +5 -0
- package/dist/clis/medium/shared.js +78 -0
- package/dist/clis/medium/user.d.ts +1 -0
- package/dist/clis/medium/user.js +15 -0
- package/dist/clis/reddit/comment.js +1 -1
- package/dist/clis/reddit/read.js +1 -1
- package/dist/clis/reddit/save.js +1 -1
- package/dist/clis/reddit/subreddit.yaml +1 -0
- package/dist/clis/reddit/subscribe.js +1 -1
- package/dist/clis/reddit/upvote.js +1 -1
- package/dist/clis/sinablog/article.d.ts +1 -0
- package/dist/clis/sinablog/article.js +14 -0
- package/dist/clis/sinablog/hot.d.ts +1 -0
- package/dist/clis/sinablog/hot.js +14 -0
- package/dist/clis/sinablog/search.d.ts +1 -0
- package/dist/clis/sinablog/search.js +51 -0
- package/dist/clis/sinablog/shared.d.ts +7 -0
- package/dist/clis/sinablog/shared.js +187 -0
- package/dist/clis/sinablog/user.d.ts +1 -0
- package/dist/clis/sinablog/user.js +15 -0
- package/dist/clis/substack/feed.d.ts +1 -0
- package/dist/clis/substack/feed.js +15 -0
- package/dist/clis/substack/publication.d.ts +1 -0
- package/dist/clis/substack/publication.js +15 -0
- package/dist/clis/substack/search.d.ts +1 -0
- package/dist/clis/substack/search.js +77 -0
- package/dist/clis/substack/shared.d.ts +4 -0
- package/dist/clis/substack/shared.js +129 -0
- package/dist/clis/tiktok/comment.yaml +66 -0
- package/dist/clis/tiktok/explore.yaml +39 -0
- package/dist/clis/tiktok/follow.yaml +39 -0
- package/dist/clis/tiktok/following.yaml +46 -0
- package/dist/clis/tiktok/friends.yaml +47 -0
- package/dist/clis/tiktok/like.yaml +38 -0
- package/dist/clis/tiktok/live.yaml +51 -0
- package/dist/clis/tiktok/notifications.yaml +52 -0
- package/dist/clis/tiktok/profile.yaml +45 -0
- package/dist/clis/tiktok/save.yaml +34 -0
- package/dist/clis/tiktok/search.yaml +46 -0
- package/dist/clis/tiktok/unfollow.yaml +44 -0
- package/dist/clis/tiktok/unlike.yaml +38 -0
- package/dist/clis/tiktok/unsave.yaml +36 -0
- package/dist/clis/tiktok/user.yaml +44 -0
- package/dist/clis/twitter/download.d.ts +1 -1
- package/dist/clis/twitter/download.js +3 -3
- package/dist/clis/twitter/followers.js +1 -1
- package/dist/clis/twitter/following.js +1 -1
- package/dist/clis/twitter/thread.js +1 -1
- package/dist/clis/twitter/timeline.d.ts +23 -0
- package/dist/clis/twitter/timeline.js +42 -14
- package/dist/clis/twitter/timeline.test.d.ts +1 -0
- package/dist/clis/twitter/timeline.test.js +102 -0
- package/dist/clis/wikipedia/random.d.ts +1 -0
- package/dist/clis/wikipedia/random.js +19 -0
- package/dist/clis/wikipedia/search.js +3 -3
- package/dist/clis/wikipedia/summary.js +4 -9
- package/dist/clis/wikipedia/trending.d.ts +1 -0
- package/dist/clis/wikipedia/trending.js +35 -0
- package/dist/clis/wikipedia/utils.d.ts +28 -0
- package/dist/clis/wikipedia/utils.js +13 -0
- package/dist/clis/xiaohongshu/creator-note-detail.js +1 -1
- package/dist/clis/xiaohongshu/creator-note-detail.test.js +2 -0
- package/dist/clis/xiaohongshu/creator-notes.test.js +2 -0
- package/dist/clis/xiaohongshu/download.js +1 -1
- package/dist/clis/xueqiu/earnings-date.yaml +69 -0
- package/dist/clis/xueqiu/search.yaml +2 -1
- package/dist/clis/xueqiu/stock.yaml +2 -0
- package/dist/clis/yahoo-finance/quote.js +1 -1
- package/dist/commanderAdapter.js +13 -7
- package/dist/daemon.js +21 -0
- package/dist/discovery.d.ts +8 -0
- package/dist/discovery.js +105 -19
- package/dist/doctor.js +3 -1
- package/dist/doctor.test.js +46 -2
- package/dist/engine.test.d.ts +0 -3
- package/dist/engine.test.js +74 -6
- package/dist/execution.d.ts +4 -2
- package/dist/execution.js +31 -7
- package/dist/explore.d.ts +76 -3
- package/dist/explore.js +11 -4
- package/dist/generate.d.ts +41 -2
- package/dist/generate.js +5 -4
- package/dist/main.js +2 -1
- package/dist/pipeline/executor.d.ts +4 -2
- package/dist/pipeline/executor.js +54 -15
- package/dist/pipeline/executor.test.js +33 -6
- package/dist/pipeline/registry.d.ts +1 -1
- package/dist/pipeline/steps/browser.d.ts +7 -7
- package/dist/pipeline/steps/browser.js +15 -7
- package/dist/pipeline/steps/fetch.d.ts +1 -1
- package/dist/pipeline/steps/fetch.js +11 -7
- package/dist/pipeline/steps/transform.d.ts +6 -5
- package/dist/pipeline/steps/transform.js +30 -9
- package/dist/pipeline/template.d.ts +6 -6
- package/dist/pipeline/template.js +43 -5
- package/dist/pipeline/template.test.js +18 -0
- package/dist/pipeline/transform.test.js +11 -0
- package/dist/plugin.d.ts +31 -0
- package/dist/plugin.js +216 -0
- package/dist/plugin.test.d.ts +4 -0
- package/dist/plugin.test.js +76 -0
- package/dist/registry-api.d.ts +11 -0
- package/dist/registry-api.js +9 -0
- package/dist/registry.d.ts +11 -0
- package/dist/registry.js +6 -1
- package/dist/synthesize.d.ts +94 -4
- package/dist/synthesize.js +5 -4
- package/dist/types.d.ts +39 -26
- package/dist/validate.js +8 -2
- package/docs/.vitepress/config.mts +6 -4
- package/docs/adapters/browser/barchart.md +6 -5
- package/docs/adapters/browser/bilibili.md +9 -0
- package/docs/adapters/browser/devto.md +35 -0
- package/docs/adapters/browser/douban.md +38 -0
- package/docs/adapters/browser/facebook.md +36 -0
- package/docs/adapters/browser/google.md +62 -0
- package/docs/adapters/browser/grok.md +26 -8
- package/docs/adapters/browser/instagram.md +46 -0
- package/docs/adapters/browser/lobsters.md +32 -0
- package/docs/adapters/browser/medium.md +32 -0
- package/docs/adapters/browser/reddit.md +9 -0
- package/docs/adapters/browser/sinablog.md +36 -0
- package/docs/adapters/browser/substack.md +38 -0
- package/docs/adapters/browser/tiktok.md +68 -0
- package/docs/adapters/browser/wikipedia.md +11 -2
- package/docs/adapters/browser/xueqiu.md +10 -0
- package/docs/adapters/browser/yahoo-finance.md +6 -5
- package/docs/adapters/desktop/antigravity.md +6 -0
- package/docs/adapters/desktop/chatgpt.md +2 -1
- package/docs/adapters/desktop/codex.md +5 -1
- package/docs/adapters/desktop/cursor.md +4 -0
- package/docs/adapters/desktop/discord.md +7 -7
- package/docs/adapters/index.md +1 -4
- package/docs/guide/getting-started.md +1 -0
- package/docs/guide/plugins.md +153 -0
- package/docs/zh/guide/plugins.md +107 -0
- package/extension/dist/background.js +91 -23
- package/extension/src/background.ts +82 -29
- package/extension/src/cdp.ts +42 -1
- package/package.json +10 -5
- package/scripts/clean-dist.cjs +13 -0
- package/src/browser/cdp.ts +71 -31
- package/src/browser/daemon-client.ts +21 -5
- package/src/browser/dom-helpers.ts +38 -7
- package/src/browser/dom-snapshot.test.ts +249 -0
- package/src/browser/dom-snapshot.ts +770 -0
- package/src/browser/index.ts +2 -0
- package/src/browser/mcp.ts +3 -1
- package/src/browser/page.ts +57 -21
- package/src/build-manifest.test.ts +70 -2
- package/src/build-manifest.ts +94 -26
- package/src/cli.ts +71 -2
- package/src/clis/barchart/greeks.ts +1 -1
- package/src/clis/barchart/options.ts +1 -1
- package/src/clis/barchart/quote.ts +1 -1
- package/src/clis/bilibili/download.ts +1 -1
- package/src/clis/bilibili/following.ts +1 -1
- package/src/clis/bilibili/subtitle.ts +1 -1
- package/src/clis/bilibili/user-videos.ts +1 -1
- package/src/clis/boss/batchgreet.ts +14 -106
- package/src/clis/boss/chatlist.ts +12 -26
- package/src/clis/boss/chatmsg.ts +16 -40
- package/src/clis/boss/common.ts +287 -0
- package/src/clis/boss/detail.ts +8 -54
- package/src/clis/boss/exchange.ts +15 -89
- package/src/clis/boss/greet.ts +23 -160
- package/src/clis/boss/invite.ts +36 -133
- package/src/clis/boss/joblist.ts +7 -36
- package/src/clis/boss/mark.ts +13 -94
- package/src/clis/boss/recommend.ts +12 -57
- package/src/clis/boss/resume.ts +19 -124
- package/src/clis/boss/search.ts +13 -66
- package/src/clis/boss/send.ts +21 -161
- package/src/clis/boss/stats.ts +19 -74
- package/src/clis/coupang/add-to-cart.ts +1 -1
- package/src/clis/devto/tag.yaml +34 -0
- package/src/clis/devto/top.yaml +29 -0
- package/src/clis/devto/user.yaml +33 -0
- package/src/clis/douban/book-hot.ts +15 -0
- package/src/clis/douban/marks.ts +135 -0
- package/src/clis/douban/movie-hot.ts +15 -0
- package/src/clis/douban/reviews.ts +127 -0
- package/src/clis/douban/search.ts +17 -0
- package/src/clis/douban/shared.ts +165 -0
- package/src/clis/douban/subject.yaml +76 -0
- package/src/clis/douban/top250.yaml +70 -0
- package/src/clis/douban/utils.ts +81 -0
- package/src/clis/facebook/add-friend.yaml +43 -0
- package/src/clis/facebook/events.yaml +44 -0
- package/src/clis/facebook/feed.yaml +63 -0
- package/src/clis/facebook/friends.yaml +42 -0
- package/src/clis/facebook/groups.yaml +50 -0
- package/src/clis/facebook/join-group.yaml +44 -0
- package/src/clis/facebook/memories.yaml +39 -0
- package/src/clis/facebook/notifications.yaml +40 -0
- package/src/clis/facebook/profile.yaml +37 -0
- package/src/clis/facebook/search.yaml +46 -0
- package/src/clis/google/news.ts +66 -0
- package/src/clis/google/search.ts +133 -0
- package/src/clis/google/suggest.ts +40 -0
- package/src/clis/google/trends.ts +44 -0
- package/src/clis/google/utils.test.ts +82 -0
- package/src/clis/google/utils.ts +24 -0
- package/src/clis/grok/ask.test.ts +53 -0
- package/src/clis/grok/ask.ts +300 -69
- package/src/clis/instagram/comment.yaml +52 -0
- package/src/clis/instagram/explore.yaml +43 -0
- package/src/clis/instagram/follow.yaml +41 -0
- package/src/clis/instagram/followers.yaml +51 -0
- package/src/clis/instagram/following.yaml +51 -0
- package/src/clis/instagram/like.yaml +46 -0
- package/src/clis/instagram/profile.yaml +42 -0
- package/src/clis/instagram/save.yaml +46 -0
- package/src/clis/instagram/saved.yaml +40 -0
- package/src/clis/instagram/search.yaml +43 -0
- package/src/clis/instagram/unfollow.yaml +38 -0
- package/src/clis/instagram/unlike.yaml +46 -0
- package/src/clis/instagram/unsave.yaml +46 -0
- package/src/clis/instagram/user.yaml +54 -0
- package/src/clis/jike/repost.ts +1 -1
- package/src/clis/jimeng/generate.yaml +1 -0
- package/src/clis/linux-do/category.yaml +1 -0
- package/src/clis/lobsters/active.yaml +29 -0
- package/src/clis/lobsters/hot.yaml +29 -0
- package/src/clis/lobsters/newest.yaml +29 -0
- package/src/clis/lobsters/tag.yaml +34 -0
- package/src/clis/medium/feed.ts +16 -0
- package/src/clis/medium/search.ts +16 -0
- package/src/clis/medium/shared.ts +83 -0
- package/src/clis/medium/user.ts +16 -0
- package/src/clis/reddit/comment.ts +1 -1
- package/src/clis/reddit/read.ts +1 -1
- package/src/clis/reddit/save.ts +1 -1
- package/src/clis/reddit/subreddit.yaml +1 -0
- package/src/clis/reddit/subscribe.ts +1 -1
- package/src/clis/reddit/upvote.ts +1 -1
- package/src/clis/sinablog/article.ts +15 -0
- package/src/clis/sinablog/hot.ts +15 -0
- package/src/clis/sinablog/search.ts +56 -0
- package/src/clis/sinablog/shared.ts +198 -0
- package/src/clis/sinablog/user.ts +16 -0
- package/src/clis/substack/feed.ts +16 -0
- package/src/clis/substack/publication.ts +16 -0
- package/src/clis/substack/search.ts +91 -0
- package/src/clis/substack/shared.ts +132 -0
- package/src/clis/tiktok/comment.yaml +66 -0
- package/src/clis/tiktok/explore.yaml +39 -0
- package/src/clis/tiktok/follow.yaml +39 -0
- package/src/clis/tiktok/following.yaml +46 -0
- package/src/clis/tiktok/friends.yaml +47 -0
- package/src/clis/tiktok/like.yaml +38 -0
- package/src/clis/tiktok/live.yaml +51 -0
- package/src/clis/tiktok/notifications.yaml +52 -0
- package/src/clis/tiktok/profile.yaml +45 -0
- package/src/clis/tiktok/save.yaml +34 -0
- package/src/clis/tiktok/search.yaml +46 -0
- package/src/clis/tiktok/unfollow.yaml +44 -0
- package/src/clis/tiktok/unlike.yaml +38 -0
- package/src/clis/tiktok/unsave.yaml +36 -0
- package/src/clis/tiktok/user.yaml +44 -0
- package/src/clis/twitter/download.ts +3 -3
- package/src/clis/twitter/followers.ts +1 -1
- package/src/clis/twitter/following.ts +1 -1
- package/src/clis/twitter/thread.ts +1 -1
- package/src/clis/twitter/timeline.test.ts +109 -0
- package/src/clis/twitter/timeline.ts +59 -19
- package/src/clis/wikipedia/random.ts +19 -0
- package/src/clis/wikipedia/search.ts +10 -4
- package/src/clis/wikipedia/summary.ts +4 -9
- package/src/clis/wikipedia/trending.ts +41 -0
- package/src/clis/wikipedia/utils.ts +31 -0
- package/src/clis/xiaohongshu/creator-note-detail.test.ts +2 -0
- package/src/clis/xiaohongshu/creator-note-detail.ts +1 -1
- package/src/clis/xiaohongshu/creator-notes.test.ts +2 -0
- package/src/clis/xiaohongshu/download.ts +1 -1
- package/src/clis/xueqiu/earnings-date.yaml +69 -0
- package/src/clis/xueqiu/search.yaml +2 -1
- package/src/clis/xueqiu/stock.yaml +2 -0
- package/src/clis/yahoo-finance/quote.ts +1 -1
- package/src/commanderAdapter.ts +17 -10
- package/src/daemon.ts +23 -0
- package/src/discovery.ts +134 -24
- package/src/doctor.test.ts +59 -2
- package/src/doctor.ts +4 -2
- package/src/engine.test.ts +79 -6
- package/src/execution.ts +42 -16
- package/src/explore.ts +77 -9
- package/src/generate.ts +58 -9
- package/src/main.ts +2 -1
- package/src/pipeline/executor.test.ts +35 -6
- package/src/pipeline/executor.ts +68 -19
- package/src/pipeline/registry.ts +3 -3
- package/src/pipeline/steps/browser.ts +24 -15
- package/src/pipeline/steps/fetch.ts +18 -13
- package/src/pipeline/steps/transform.ts +40 -15
- package/src/pipeline/template.test.ts +18 -0
- package/src/pipeline/template.ts +86 -13
- package/src/pipeline/transform.test.ts +15 -2
- package/src/plugin.test.ts +86 -0
- package/src/plugin.ts +254 -0
- package/src/registry-api.ts +12 -0
- package/src/registry.ts +19 -1
- package/src/synthesize.ts +102 -21
- package/src/types.ts +44 -12
- package/src/validate.ts +19 -4
- package/tests/e2e/browser-public.test.ts +11 -0
- package/tests/e2e/public-commands.test.ts +64 -0
- package/dist/clis/feishu/new.d.ts +0 -1
- package/dist/clis/feishu/new.js +0 -27
- package/dist/clis/feishu/read.d.ts +0 -1
- package/dist/clis/feishu/read.js +0 -40
- package/dist/clis/feishu/search.d.ts +0 -1
- package/dist/clis/feishu/search.js +0 -30
- package/dist/clis/feishu/send.d.ts +0 -1
- package/dist/clis/feishu/send.js +0 -39
- package/dist/clis/feishu/status.d.ts +0 -1
- package/dist/clis/feishu/status.js +0 -28
- package/dist/clis/neteasemusic/like.d.ts +0 -1
- package/dist/clis/neteasemusic/like.js +0 -25
- package/dist/clis/neteasemusic/lyrics.d.ts +0 -1
- package/dist/clis/neteasemusic/lyrics.js +0 -47
- package/dist/clis/neteasemusic/next.d.ts +0 -1
- package/dist/clis/neteasemusic/next.js +0 -26
- package/dist/clis/neteasemusic/play.d.ts +0 -1
- package/dist/clis/neteasemusic/play.js +0 -26
- package/dist/clis/neteasemusic/playing.d.ts +0 -1
- package/dist/clis/neteasemusic/playing.js +0 -59
- package/dist/clis/neteasemusic/playlist.d.ts +0 -1
- package/dist/clis/neteasemusic/playlist.js +0 -46
- package/dist/clis/neteasemusic/prev.d.ts +0 -1
- package/dist/clis/neteasemusic/prev.js +0 -25
- package/dist/clis/neteasemusic/search.d.ts +0 -1
- package/dist/clis/neteasemusic/search.js +0 -52
- package/dist/clis/neteasemusic/status.d.ts +0 -1
- package/dist/clis/neteasemusic/status.js +0 -16
- package/dist/clis/neteasemusic/volume.d.ts +0 -1
- package/dist/clis/neteasemusic/volume.js +0 -54
- package/dist/clis/wechat/chats.d.ts +0 -1
- package/dist/clis/wechat/chats.js +0 -28
- package/dist/clis/wechat/contacts.d.ts +0 -1
- package/dist/clis/wechat/contacts.js +0 -28
- package/dist/clis/wechat/read.d.ts +0 -1
- package/dist/clis/wechat/read.js +0 -58
- package/dist/clis/wechat/search.d.ts +0 -1
- package/dist/clis/wechat/search.js +0 -31
- package/dist/clis/wechat/send.d.ts +0 -1
- package/dist/clis/wechat/send.js +0 -42
- package/dist/clis/wechat/status.d.ts +0 -1
- package/dist/clis/wechat/status.js +0 -29
- package/dist/pipeline.d.ts +0 -7
- package/dist/pipeline.js +0 -7
- package/docs/adapters/browser/github.md +0 -26
- package/docs/adapters/desktop/feishu.md +0 -20
- package/docs/adapters/desktop/neteasemusic.md +0 -31
- package/docs/adapters/desktop/wechat.md +0 -28
- package/src/clis/antigravity/README.md +0 -5
- package/src/clis/antigravity/README.zh-CN.md +0 -51
- package/src/clis/chaoxing/README.md +0 -14
- package/src/clis/chaoxing/README.zh-CN.md +0 -35
- package/src/clis/chatgpt/README.md +0 -5
- package/src/clis/chatgpt/README.zh-CN.md +0 -44
- package/src/clis/chatwise/README.md +0 -5
- package/src/clis/chatwise/README.zh-CN.md +0 -38
- package/src/clis/codex/README.md +0 -5
- package/src/clis/codex/README.zh-CN.md +0 -33
- package/src/clis/cursor/README.md +0 -5
- package/src/clis/cursor/README.zh-CN.md +0 -33
- package/src/clis/discord-app/README.md +0 -5
- package/src/clis/discord-app/README.zh-CN.md +0 -28
- package/src/clis/feishu/README.md +0 -5
- package/src/clis/feishu/README.zh-CN.md +0 -20
- package/src/clis/feishu/new.ts +0 -32
- package/src/clis/feishu/read.ts +0 -48
- package/src/clis/feishu/search.ts +0 -35
- package/src/clis/feishu/send.ts +0 -46
- package/src/clis/feishu/status.ts +0 -34
- package/src/clis/neteasemusic/README.md +0 -5
- package/src/clis/neteasemusic/README.zh-CN.md +0 -31
- package/src/clis/neteasemusic/like.ts +0 -28
- package/src/clis/neteasemusic/lyrics.ts +0 -53
- package/src/clis/neteasemusic/next.ts +0 -30
- package/src/clis/neteasemusic/play.ts +0 -30
- package/src/clis/neteasemusic/playing.ts +0 -62
- package/src/clis/neteasemusic/playlist.ts +0 -51
- package/src/clis/neteasemusic/prev.ts +0 -29
- package/src/clis/neteasemusic/search.ts +0 -58
- package/src/clis/neteasemusic/status.ts +0 -18
- package/src/clis/neteasemusic/volume.ts +0 -61
- package/src/clis/notion/README.md +0 -5
- package/src/clis/notion/README.zh-CN.md +0 -29
- package/src/clis/wechat/README.md +0 -5
- package/src/clis/wechat/README.zh-CN.md +0 -28
- package/src/clis/wechat/chats.ts +0 -33
- package/src/clis/wechat/contacts.ts +0 -33
- package/src/clis/wechat/read.ts +0 -72
- package/src/clis/wechat/search.ts +0 -36
- package/src/clis/wechat/send.ts +0 -49
- package/src/clis/wechat/status.ts +0 -35
- package/src/pipeline.ts +0 -8
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* BOSS直聘 exchange — request phone/wechat exchange with a candidate.
|
|
3
|
-
*
|
|
4
|
-
* Uses POST /wapi/zpchat/exchange/request to send an exchange request.
|
|
5
3
|
*/
|
|
6
4
|
import { cli, Strategy } from '../../registry.js';
|
|
7
|
-
import
|
|
5
|
+
import { requirePage, navigateToChat, bossFetch, findFriendByUid, verbose } from './common.js';
|
|
8
6
|
|
|
9
7
|
cli({
|
|
10
8
|
site: 'boss',
|
|
@@ -12,110 +10,38 @@ cli({
|
|
|
12
10
|
description: 'BOSS直聘交换联系方式(请求手机/微信)',
|
|
13
11
|
domain: 'www.zhipin.com',
|
|
14
12
|
strategy: Strategy.COOKIE,
|
|
13
|
+
navigateBefore: false,
|
|
15
14
|
browser: true,
|
|
16
15
|
args: [
|
|
17
|
-
{ name: 'uid', required: true, help: 'Encrypted UID of the candidate' },
|
|
16
|
+
{ name: 'uid', required: true, positional: true, help: 'Encrypted UID of the candidate' },
|
|
18
17
|
{ name: 'type', default: 'phone', choices: ['phone', 'wechat'], help: 'Exchange type: phone or wechat' },
|
|
19
18
|
],
|
|
20
19
|
columns: ['status', 'detail'],
|
|
21
|
-
func: async (page
|
|
22
|
-
|
|
20
|
+
func: async (page, kwargs) => {
|
|
21
|
+
requirePage(page);
|
|
23
22
|
|
|
24
|
-
const uid = kwargs.uid;
|
|
25
23
|
const exchangeType = kwargs.type || 'phone';
|
|
24
|
+
verbose(`Requesting ${exchangeType} exchange for ${kwargs.uid}...`);
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
console.error(`[opencli:boss] Requesting ${exchangeType} exchange for ${uid}...`);
|
|
29
|
-
}
|
|
26
|
+
await navigateToChat(page);
|
|
30
27
|
|
|
31
|
-
await page.
|
|
32
|
-
|
|
28
|
+
const friend = await findFriendByUid(page, kwargs.uid, { checkGreetList: true });
|
|
29
|
+
if (!friend) throw new Error('未找到该候选人');
|
|
33
30
|
|
|
34
|
-
// Find candidate
|
|
35
|
-
let friend: any = null;
|
|
36
|
-
|
|
37
|
-
// Check greet list
|
|
38
|
-
const greetData: any = await page.evaluate(`
|
|
39
|
-
async () => {
|
|
40
|
-
return new Promise((resolve, reject) => {
|
|
41
|
-
const xhr = new XMLHttpRequest();
|
|
42
|
-
xhr.open('GET', 'https://www.zhipin.com/wapi/zprelation/friend/greetRecSortList', true);
|
|
43
|
-
xhr.withCredentials = true;
|
|
44
|
-
xhr.timeout = 15000;
|
|
45
|
-
xhr.setRequestHeader('Accept', 'application/json');
|
|
46
|
-
xhr.onload = () => { try { resolve(JSON.parse(xhr.responseText)); } catch(e) { reject(e); } };
|
|
47
|
-
xhr.onerror = () => reject(new Error('Network Error'));
|
|
48
|
-
xhr.send();
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
`);
|
|
52
|
-
|
|
53
|
-
if (greetData.code === 0) {
|
|
54
|
-
friend = (greetData.zpData?.friendList || []).find((f: any) => f.encryptUid === uid);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (!friend) {
|
|
58
|
-
const friendData: any = await page.evaluate(`
|
|
59
|
-
async () => {
|
|
60
|
-
return new Promise((resolve, reject) => {
|
|
61
|
-
const xhr = new XMLHttpRequest();
|
|
62
|
-
xhr.open('GET', 'https://www.zhipin.com/wapi/zprelation/friend/getBossFriendListV2.json?page=1&status=0&jobId=0', true);
|
|
63
|
-
xhr.withCredentials = true;
|
|
64
|
-
xhr.timeout = 15000;
|
|
65
|
-
xhr.setRequestHeader('Accept', 'application/json');
|
|
66
|
-
xhr.onload = () => { try { resolve(JSON.parse(xhr.responseText)); } catch(e) { reject(e); } };
|
|
67
|
-
xhr.onerror = () => reject(new Error('Network Error'));
|
|
68
|
-
xhr.send();
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
`);
|
|
72
|
-
if (friendData.code === 0) {
|
|
73
|
-
friend = (friendData.zpData?.friendList || []).find((f: any) => f.encryptUid === uid);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (!friend) {
|
|
78
|
-
throw new Error('未找到该候选人');
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const numericUid = friend.uid;
|
|
82
31
|
const friendName = friend.name || '候选人';
|
|
83
|
-
const securityId = friend.securityId || '';
|
|
84
|
-
|
|
85
|
-
// type mapping from JS source: 1=phone, 2=wechat, 4=resume
|
|
86
32
|
const typeId = exchangeType === 'wechat' ? 2 : 1;
|
|
87
33
|
|
|
88
|
-
// Params from JS: {type, securityId, uniqueId, name}
|
|
89
34
|
const params = new URLSearchParams({
|
|
90
35
|
type: String(typeId),
|
|
91
|
-
securityId: securityId,
|
|
92
|
-
uniqueId: String(
|
|
36
|
+
securityId: friend.securityId || '',
|
|
37
|
+
uniqueId: String(friend.uid),
|
|
93
38
|
name: friendName,
|
|
94
39
|
});
|
|
95
40
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const xhr = new XMLHttpRequest();
|
|
101
|
-
xhr.open('POST', 'https://www.zhipin.com/wapi/zpchat/exchange/request', true);
|
|
102
|
-
xhr.withCredentials = true;
|
|
103
|
-
xhr.timeout = 15000;
|
|
104
|
-
xhr.setRequestHeader('Accept', 'application/json');
|
|
105
|
-
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
|
106
|
-
xhr.onload = () => { try { resolve(JSON.parse(xhr.responseText)); } catch(e) { reject(new Error('JSON parse failed')); } };
|
|
107
|
-
xhr.onerror = () => reject(new Error('Network Error'));
|
|
108
|
-
xhr.send(${JSON.stringify(params.toString())});
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
`);
|
|
112
|
-
|
|
113
|
-
if (data.code !== 0) {
|
|
114
|
-
if (data.code === 7 || data.code === 37) {
|
|
115
|
-
throw new Error('Cookie 已过期!请在当前 Chrome 浏览器中重新登录 BOSS 直聘。');
|
|
116
|
-
}
|
|
117
|
-
throw new Error(`交换请求失败: ${data.message} (code=${data.code})`);
|
|
118
|
-
}
|
|
41
|
+
await bossFetch(page, 'https://www.zhipin.com/wapi/zpchat/exchange/request', {
|
|
42
|
+
method: 'POST',
|
|
43
|
+
body: params.toString(),
|
|
44
|
+
});
|
|
119
45
|
|
|
120
46
|
const typeLabel = exchangeType === 'wechat' ? '微信' : '手机号';
|
|
121
47
|
return [{
|
package/src/clis/boss/greet.ts
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* BOSS直聘 greet — send greeting to a new candidate (initiate chat).
|
|
3
|
-
*
|
|
4
|
-
* This is different from send.ts which messages existing contacts.
|
|
5
|
-
* For new candidates (from recommend list), we navigate to their chat page
|
|
6
|
-
* and use UI automation to send the greeting message.
|
|
7
|
-
*
|
|
8
|
-
* The greetRecSortList provides candidates who have applied or been recommended.
|
|
9
|
-
* We click on them in the list and send a greeting.
|
|
10
3
|
*/
|
|
11
4
|
import { cli, Strategy } from '../../registry.js';
|
|
12
|
-
import
|
|
5
|
+
import {
|
|
6
|
+
requirePage, navigateToChat, findFriendByUid,
|
|
7
|
+
clickCandidateInList, typeAndSendMessage, verbose,
|
|
8
|
+
} from './common.js';
|
|
13
9
|
|
|
14
10
|
cli({
|
|
15
11
|
site: 'boss',
|
|
@@ -17,180 +13,47 @@ cli({
|
|
|
17
13
|
description: 'BOSS直聘向新候选人发送招呼(开始聊天)',
|
|
18
14
|
domain: 'www.zhipin.com',
|
|
19
15
|
strategy: Strategy.COOKIE,
|
|
16
|
+
navigateBefore: false,
|
|
20
17
|
browser: true,
|
|
21
18
|
args: [
|
|
22
|
-
{ name: 'uid', required: true, help: 'Encrypted UID of the candidate (from recommend)' },
|
|
19
|
+
{ name: 'uid', positional: true, required: true, help: 'Encrypted UID of the candidate (from recommend)' },
|
|
23
20
|
{ name: 'security-id', required: true, help: 'Security ID of the candidate' },
|
|
24
21
|
{ name: 'job-id', required: true, help: 'Encrypted job ID' },
|
|
25
22
|
{ name: 'text', default: '', help: 'Custom greeting message (uses default template if empty)' },
|
|
26
23
|
],
|
|
27
24
|
columns: ['status', 'detail'],
|
|
28
|
-
func: async (page
|
|
29
|
-
|
|
25
|
+
func: async (page, kwargs) => {
|
|
26
|
+
requirePage(page);
|
|
27
|
+
verbose(`Greeting candidate ${kwargs.uid}...`);
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
const securityId = kwargs['security-id'];
|
|
33
|
-
const jobId = kwargs['job-id'];
|
|
34
|
-
const text = kwargs.text;
|
|
29
|
+
await navigateToChat(page, 3);
|
|
35
30
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
await page.goto('https://www.zhipin.com/web/chat/index');
|
|
42
|
-
await page.wait({ time: 3 });
|
|
43
|
-
|
|
44
|
-
// Find the candidate in the greet list by encryptUid
|
|
45
|
-
const listData: any = await page.evaluate(`
|
|
46
|
-
async () => {
|
|
47
|
-
return new Promise((resolve, reject) => {
|
|
48
|
-
const xhr = new XMLHttpRequest();
|
|
49
|
-
xhr.open('GET', 'https://www.zhipin.com/wapi/zprelation/friend/greetRecSortList', true);
|
|
50
|
-
xhr.withCredentials = true;
|
|
51
|
-
xhr.timeout = 15000;
|
|
52
|
-
xhr.setRequestHeader('Accept', 'application/json');
|
|
53
|
-
xhr.onload = () => { try { resolve(JSON.parse(xhr.responseText)); } catch(e) { reject(e); } };
|
|
54
|
-
xhr.onerror = () => reject(new Error('Network Error'));
|
|
55
|
-
xhr.send();
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
`);
|
|
59
|
-
|
|
60
|
-
if (listData.code !== 0) {
|
|
61
|
-
if (listData.code === 7 || listData.code === 37) {
|
|
62
|
-
throw new Error('Cookie 已过期!请在当前 Chrome 浏览器中重新登录 BOSS 直聘。');
|
|
63
|
-
}
|
|
64
|
-
throw new Error(`获取候选人列表失败: ${listData.message}`);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Also check the regular friend list
|
|
68
|
-
let target: any = null;
|
|
69
|
-
const greetList = listData.zpData?.friendList || [];
|
|
70
|
-
target = greetList.find((f: any) => f.encryptUid === uid);
|
|
71
|
-
|
|
72
|
-
let numericUid: string | null = null;
|
|
73
|
-
let friendName = '候选人';
|
|
74
|
-
|
|
75
|
-
if (target) {
|
|
76
|
-
numericUid = target.uid;
|
|
77
|
-
friendName = target.name || friendName;
|
|
78
|
-
}
|
|
31
|
+
// Find candidate in greet list or friend list
|
|
32
|
+
const friend = await findFriendByUid(page, kwargs.uid, {
|
|
33
|
+
maxPages: 1,
|
|
34
|
+
checkGreetList: true,
|
|
35
|
+
});
|
|
79
36
|
|
|
80
|
-
if (!
|
|
81
|
-
// Try to find in friend list
|
|
82
|
-
const friendData: any = await page.evaluate(`
|
|
83
|
-
async () => {
|
|
84
|
-
return new Promise((resolve, reject) => {
|
|
85
|
-
const xhr = new XMLHttpRequest();
|
|
86
|
-
xhr.open('GET', 'https://www.zhipin.com/wapi/zprelation/friend/getBossFriendListV2.json?page=1&status=0&jobId=0', true);
|
|
87
|
-
xhr.withCredentials = true;
|
|
88
|
-
xhr.timeout = 15000;
|
|
89
|
-
xhr.setRequestHeader('Accept', 'application/json');
|
|
90
|
-
xhr.onload = () => { try { resolve(JSON.parse(xhr.responseText)); } catch(e) { reject(e); } };
|
|
91
|
-
xhr.onerror = () => reject(new Error('Network Error'));
|
|
92
|
-
xhr.send();
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
`);
|
|
96
|
-
|
|
97
|
-
if (friendData.code === 0) {
|
|
98
|
-
const allFriends = friendData.zpData?.friendList || [];
|
|
99
|
-
const found = allFriends.find((f: any) => f.encryptUid === uid);
|
|
100
|
-
if (found) {
|
|
101
|
-
numericUid = found.uid;
|
|
102
|
-
friendName = found.name || friendName;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (!numericUid) {
|
|
37
|
+
if (!friend) {
|
|
108
38
|
throw new Error('未找到该候选人,请确认 uid 是否正确(可从 recommend 命令获取)');
|
|
109
39
|
}
|
|
110
40
|
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
async () => {
|
|
114
|
-
const item = document.querySelector('#_${numericUid}-0') || document.querySelector('[id^="_${numericUid}"]');
|
|
115
|
-
if (item) {
|
|
116
|
-
item.click();
|
|
117
|
-
return { clicked: true, id: item.id };
|
|
118
|
-
}
|
|
119
|
-
const items = document.querySelectorAll('.geek-item');
|
|
120
|
-
for (const el of items) {
|
|
121
|
-
if (el.id && el.id.startsWith('_${numericUid}')) {
|
|
122
|
-
el.click();
|
|
123
|
-
return { clicked: true, id: el.id };
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return { clicked: false };
|
|
127
|
-
}
|
|
128
|
-
`);
|
|
41
|
+
const numericUid = friend.uid;
|
|
42
|
+
const friendName = friend.name || '候选人';
|
|
129
43
|
|
|
130
|
-
|
|
44
|
+
const clicked = await clickCandidateInList(page, numericUid);
|
|
45
|
+
if (!clicked) {
|
|
131
46
|
throw new Error('无法在聊天列表中找到该用户,候选人可能不在当前列表中');
|
|
132
47
|
}
|
|
133
48
|
|
|
134
49
|
await page.wait({ time: 2 });
|
|
135
50
|
|
|
136
|
-
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
const typed: any = await page.evaluate(`
|
|
140
|
-
async () => {
|
|
141
|
-
const selectors = [
|
|
142
|
-
'.chat-editor [contenteditable="true"]',
|
|
143
|
-
'.chat-input [contenteditable="true"]',
|
|
144
|
-
'.message-editor [contenteditable="true"]',
|
|
145
|
-
'.chat-conversation [contenteditable="true"]',
|
|
146
|
-
'[contenteditable="true"]',
|
|
147
|
-
'textarea',
|
|
148
|
-
];
|
|
149
|
-
|
|
150
|
-
for (const sel of selectors) {
|
|
151
|
-
const el = document.querySelector(sel);
|
|
152
|
-
if (el && el.offsetParent !== null) {
|
|
153
|
-
el.focus();
|
|
154
|
-
if (el.tagName === 'TEXTAREA' || el.tagName === 'INPUT') {
|
|
155
|
-
el.value = ${JSON.stringify(msgText)};
|
|
156
|
-
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
157
|
-
} else {
|
|
158
|
-
el.textContent = '';
|
|
159
|
-
el.focus();
|
|
160
|
-
document.execCommand('insertText', false, ${JSON.stringify(msgText)});
|
|
161
|
-
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
162
|
-
}
|
|
163
|
-
return { found: true, selector: sel };
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
return { found: false };
|
|
167
|
-
}
|
|
168
|
-
`);
|
|
169
|
-
|
|
170
|
-
if (!typed.found) {
|
|
51
|
+
const msgText = kwargs.text || '你好,请问您对这个职位感兴趣吗?';
|
|
52
|
+
const sent = await typeAndSendMessage(page, msgText);
|
|
53
|
+
if (!sent) {
|
|
171
54
|
throw new Error('找不到消息输入框');
|
|
172
55
|
}
|
|
173
56
|
|
|
174
|
-
await page.wait({ time: 0.5 });
|
|
175
|
-
|
|
176
|
-
// Click send button
|
|
177
|
-
const sent: any = await page.evaluate(`
|
|
178
|
-
async () => {
|
|
179
|
-
const btn = document.querySelector('.conversation-editor .submit')
|
|
180
|
-
|| document.querySelector('.submit-content .submit')
|
|
181
|
-
|| document.querySelector('.conversation-operate .submit');
|
|
182
|
-
if (btn) {
|
|
183
|
-
btn.click();
|
|
184
|
-
return { clicked: true };
|
|
185
|
-
}
|
|
186
|
-
return { clicked: false };
|
|
187
|
-
}
|
|
188
|
-
`);
|
|
189
|
-
|
|
190
|
-
if (!sent.clicked) {
|
|
191
|
-
await page.pressKey('Enter');
|
|
192
|
-
}
|
|
193
|
-
|
|
194
57
|
await page.wait({ time: 1 });
|
|
195
58
|
|
|
196
59
|
return [{ status: '✅ 招呼已发送', detail: `已向 ${friendName} 发送: ${msgText}` }];
|
package/src/clis/boss/invite.ts
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* BOSS直聘 invite — send interview invitation to a candidate.
|
|
3
|
-
*
|
|
4
|
-
* Uses POST /wapi/zpinterview/boss/interview/invite to send interview invitations.
|
|
5
|
-
* Address and contact info come from the boss's saved settings.
|
|
6
3
|
*/
|
|
7
4
|
import { cli, Strategy } from '../../registry.js';
|
|
8
|
-
import
|
|
5
|
+
import { requirePage, navigateToChat, bossFetch, findFriendByUid, verbose } from './common.js';
|
|
9
6
|
|
|
10
7
|
cli({
|
|
11
8
|
site: 'boss',
|
|
@@ -13,165 +10,71 @@ cli({
|
|
|
13
10
|
description: 'BOSS直聘发送面试邀请',
|
|
14
11
|
domain: 'www.zhipin.com',
|
|
15
12
|
strategy: Strategy.COOKIE,
|
|
13
|
+
navigateBefore: false,
|
|
16
14
|
browser: true,
|
|
17
15
|
args: [
|
|
18
|
-
{ name: 'uid', required: true, help: 'Encrypted UID of the candidate' },
|
|
16
|
+
{ name: 'uid', positional: true, required: true, help: 'Encrypted UID of the candidate' },
|
|
19
17
|
{ name: 'time', required: true, help: 'Interview time (e.g. 2025-04-01 14:00)' },
|
|
20
18
|
{ name: 'address', default: '', help: 'Interview address (uses saved address if empty)' },
|
|
21
19
|
{ name: 'contact', default: '', help: 'Contact person name (uses saved contact if empty)' },
|
|
22
20
|
],
|
|
23
21
|
columns: ['status', 'detail'],
|
|
24
|
-
func: async (page
|
|
25
|
-
|
|
22
|
+
func: async (page, kwargs) => {
|
|
23
|
+
requirePage(page);
|
|
24
|
+
verbose(`Sending interview invitation to ${kwargs.uid}...`);
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
const timeStr = kwargs.time;
|
|
29
|
-
const address = kwargs.address;
|
|
30
|
-
const contact = kwargs.contact;
|
|
26
|
+
await navigateToChat(page);
|
|
31
27
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
await page.goto('https://www.zhipin.com/web/chat/index');
|
|
37
|
-
await page.wait({ time: 2 });
|
|
38
|
-
|
|
39
|
-
// Get candidate info
|
|
40
|
-
let friend: any = null;
|
|
28
|
+
const friend = await findFriendByUid(page, kwargs.uid, { checkGreetList: true });
|
|
29
|
+
if (!friend) throw new Error('未找到该候选人');
|
|
41
30
|
|
|
42
|
-
// Check greet list first
|
|
43
|
-
const greetData: any = await page.evaluate(`
|
|
44
|
-
async () => {
|
|
45
|
-
return new Promise((resolve, reject) => {
|
|
46
|
-
const xhr = new XMLHttpRequest();
|
|
47
|
-
xhr.open('GET', 'https://www.zhipin.com/wapi/zprelation/friend/greetRecSortList', true);
|
|
48
|
-
xhr.withCredentials = true;
|
|
49
|
-
xhr.timeout = 15000;
|
|
50
|
-
xhr.setRequestHeader('Accept', 'application/json');
|
|
51
|
-
xhr.onload = () => { try { resolve(JSON.parse(xhr.responseText)); } catch(e) { reject(e); } };
|
|
52
|
-
xhr.onerror = () => reject(new Error('Network Error'));
|
|
53
|
-
xhr.send();
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
`);
|
|
57
|
-
|
|
58
|
-
if (greetData.code === 0) {
|
|
59
|
-
friend = (greetData.zpData?.friendList || []).find((f: any) => f.encryptUid === uid);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (!friend) {
|
|
63
|
-
const friendData: any = await page.evaluate(`
|
|
64
|
-
async () => {
|
|
65
|
-
return new Promise((resolve, reject) => {
|
|
66
|
-
const xhr = new XMLHttpRequest();
|
|
67
|
-
xhr.open('GET', 'https://www.zhipin.com/wapi/zprelation/friend/getBossFriendListV2.json?page=1&status=0&jobId=0', true);
|
|
68
|
-
xhr.withCredentials = true;
|
|
69
|
-
xhr.timeout = 15000;
|
|
70
|
-
xhr.setRequestHeader('Accept', 'application/json');
|
|
71
|
-
xhr.onload = () => { try { resolve(JSON.parse(xhr.responseText)); } catch(e) { reject(e); } };
|
|
72
|
-
xhr.onerror = () => reject(new Error('Network Error'));
|
|
73
|
-
xhr.send();
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
`);
|
|
77
|
-
if (friendData.code === 0) {
|
|
78
|
-
friend = (friendData.zpData?.friendList || []).find((f: any) => f.encryptUid === uid);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (!friend) {
|
|
83
|
-
throw new Error('未找到该候选人');
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const numericUid = friend.uid;
|
|
87
31
|
const friendName = friend.name || '候选人';
|
|
88
|
-
const securityId = friend.securityId || '';
|
|
89
|
-
const encJobId = friend.encryptJobId || '';
|
|
90
32
|
|
|
91
33
|
// Get saved contact info
|
|
92
|
-
const contactData
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
xhr.timeout = 10000;
|
|
99
|
-
xhr.setRequestHeader('Accept', 'application/json');
|
|
100
|
-
xhr.onload = () => { try { resolve(JSON.parse(xhr.responseText)); } catch(e) { reject(e); } };
|
|
101
|
-
xhr.onerror = () => reject(new Error('Network Error'));
|
|
102
|
-
xhr.send();
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
`);
|
|
106
|
-
|
|
107
|
-
const contactId = contactData.zpData?.contactId || '';
|
|
108
|
-
const contactName = contact || contactData.zpData?.contactName || '';
|
|
34
|
+
const contactData = await bossFetch(
|
|
35
|
+
page,
|
|
36
|
+
'https://www.zhipin.com/wapi/zpinterview/boss/interview/contactInit',
|
|
37
|
+
{ allowNonZero: true, timeout: 10_000 },
|
|
38
|
+
);
|
|
39
|
+
const contactName = kwargs.contact || contactData.zpData?.contactName || '';
|
|
109
40
|
const contactPhone = contactData.zpData?.contactPhone || '';
|
|
41
|
+
const contactId = contactData.zpData?.contactId || '';
|
|
110
42
|
|
|
111
43
|
// Get saved address
|
|
112
|
-
const addressData
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
xhr.withCredentials = true;
|
|
118
|
-
xhr.timeout = 10000;
|
|
119
|
-
xhr.setRequestHeader('Accept', 'application/json');
|
|
120
|
-
xhr.onload = () => { try { resolve(JSON.parse(xhr.responseText)); } catch(e) { reject(e); } };
|
|
121
|
-
xhr.onerror = () => reject(new Error('Network Error'));
|
|
122
|
-
xhr.send();
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
`);
|
|
126
|
-
|
|
44
|
+
const addressData = await bossFetch(
|
|
45
|
+
page,
|
|
46
|
+
'https://www.zhipin.com/wapi/zpinterview/boss/interview/listAddress',
|
|
47
|
+
{ allowNonZero: true, timeout: 10_000 },
|
|
48
|
+
);
|
|
127
49
|
const savedAddress = addressData.zpData?.list?.[0] || {};
|
|
128
|
-
const addressText = address || savedAddress.cityAddressText || savedAddress.addressText || '';
|
|
50
|
+
const addressText = kwargs.address || savedAddress.cityAddressText || savedAddress.addressText || '';
|
|
129
51
|
|
|
130
52
|
// Parse interview time
|
|
131
|
-
const interviewTime = new Date(
|
|
53
|
+
const interviewTime = new Date(kwargs.time).getTime();
|
|
132
54
|
if (isNaN(interviewTime)) {
|
|
133
|
-
throw new Error(`时间格式错误: ${
|
|
55
|
+
throw new Error(`时间格式错误: ${kwargs.time},请使用格式如 2025-04-01 14:00`);
|
|
134
56
|
}
|
|
135
57
|
|
|
136
|
-
// Send interview invitation
|
|
137
58
|
const params = new URLSearchParams({
|
|
138
|
-
uid: String(
|
|
139
|
-
securityId: securityId,
|
|
140
|
-
encryptJobId:
|
|
59
|
+
uid: String(friend.uid),
|
|
60
|
+
securityId: friend.securityId || '',
|
|
61
|
+
encryptJobId: friend.encryptJobId || '',
|
|
141
62
|
interviewTime: String(interviewTime),
|
|
142
|
-
contactId
|
|
143
|
-
contactName
|
|
144
|
-
contactPhone
|
|
63
|
+
contactId,
|
|
64
|
+
contactName,
|
|
65
|
+
contactPhone,
|
|
145
66
|
address: addressText,
|
|
146
|
-
interviewType: '1',
|
|
67
|
+
interviewType: '1',
|
|
147
68
|
});
|
|
148
69
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
xhr.open('POST', 'https://www.zhipin.com/wapi/zpinterview/boss/interview/invite.json', true);
|
|
154
|
-
xhr.withCredentials = true;
|
|
155
|
-
xhr.timeout = 15000;
|
|
156
|
-
xhr.setRequestHeader('Accept', 'application/json');
|
|
157
|
-
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
|
158
|
-
xhr.onload = () => { try { resolve(JSON.parse(xhr.responseText)); } catch(e) { reject(new Error('JSON parse failed')); } };
|
|
159
|
-
xhr.onerror = () => reject(new Error('Network Error'));
|
|
160
|
-
xhr.send(${JSON.stringify(params.toString())});
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
`);
|
|
164
|
-
|
|
165
|
-
if (data.code !== 0) {
|
|
166
|
-
if (data.code === 7 || data.code === 37) {
|
|
167
|
-
throw new Error('Cookie 已过期!请在当前 Chrome 浏览器中重新登录 BOSS 直聘。');
|
|
168
|
-
}
|
|
169
|
-
throw new Error(`面试邀请发送失败: ${data.message} (code=${data.code})`);
|
|
170
|
-
}
|
|
70
|
+
await bossFetch(page, 'https://www.zhipin.com/wapi/zpinterview/boss/interview/invite.json', {
|
|
71
|
+
method: 'POST',
|
|
72
|
+
body: params.toString(),
|
|
73
|
+
});
|
|
171
74
|
|
|
172
75
|
return [{
|
|
173
76
|
status: '✅ 面试邀请已发送',
|
|
174
|
-
detail: `已向 ${friendName} 发送面试邀请\n时间: ${
|
|
77
|
+
detail: `已向 ${friendName} 发送面试邀请\n时间: ${kwargs.time}\n地点: ${addressText}\n联系人: ${contactName}`,
|
|
175
78
|
}];
|
|
176
79
|
},
|
|
177
80
|
});
|
package/src/clis/boss/joblist.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* BOSS直聘 job list — list my published jobs via boss API.
|
|
3
|
-
*
|
|
4
|
-
* Uses /wapi/zpjob/job/chatted/jobList to get job list with status info.
|
|
5
3
|
*/
|
|
6
4
|
import { cli, Strategy } from '../../registry.js';
|
|
7
|
-
import
|
|
5
|
+
import { requirePage, navigateToChat, bossFetch, verbose } from './common.js';
|
|
8
6
|
|
|
9
7
|
cli({
|
|
10
8
|
site: 'boss',
|
|
@@ -12,46 +10,19 @@ cli({
|
|
|
12
10
|
description: 'BOSS直聘查看我发布的职位列表',
|
|
13
11
|
domain: 'www.zhipin.com',
|
|
14
12
|
strategy: Strategy.COOKIE,
|
|
13
|
+
navigateBefore: false,
|
|
15
14
|
browser: true,
|
|
16
15
|
args: [],
|
|
17
16
|
columns: ['job_name', 'salary', 'city', 'status', 'encrypt_job_id'],
|
|
18
|
-
func: async (page
|
|
19
|
-
|
|
17
|
+
func: async (page, kwargs) => {
|
|
18
|
+
requirePage(page);
|
|
19
|
+
verbose('Fetching job list...');
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
console.error('[opencli:boss] Fetching job list...');
|
|
23
|
-
}
|
|
21
|
+
await navigateToChat(page);
|
|
24
22
|
|
|
25
|
-
await page
|
|
26
|
-
await page.wait({ time: 2 });
|
|
27
|
-
|
|
28
|
-
const targetUrl = 'https://www.zhipin.com/wapi/zpjob/job/chatted/jobList';
|
|
29
|
-
|
|
30
|
-
const data: any = await page.evaluate(`
|
|
31
|
-
async () => {
|
|
32
|
-
return new Promise((resolve, reject) => {
|
|
33
|
-
const xhr = new XMLHttpRequest();
|
|
34
|
-
xhr.open('GET', '${targetUrl}', true);
|
|
35
|
-
xhr.withCredentials = true;
|
|
36
|
-
xhr.timeout = 15000;
|
|
37
|
-
xhr.setRequestHeader('Accept', 'application/json');
|
|
38
|
-
xhr.onload = () => { try { resolve(JSON.parse(xhr.responseText)); } catch(e) { reject(new Error('JSON parse failed')); } };
|
|
39
|
-
xhr.onerror = () => reject(new Error('Network Error'));
|
|
40
|
-
xhr.ontimeout = () => reject(new Error('Timeout'));
|
|
41
|
-
xhr.send();
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
`);
|
|
45
|
-
|
|
46
|
-
if (data.code !== 0) {
|
|
47
|
-
if (data.code === 7 || data.code === 37) {
|
|
48
|
-
throw new Error('Cookie 已过期!请在当前 Chrome 浏览器中重新登录 BOSS 直聘。');
|
|
49
|
-
}
|
|
50
|
-
throw new Error(`API error: ${data.message} (code=${data.code})`);
|
|
51
|
-
}
|
|
23
|
+
const data = await bossFetch(page, 'https://www.zhipin.com/wapi/zpjob/job/chatted/jobList');
|
|
52
24
|
|
|
53
25
|
const jobs = data.zpData || [];
|
|
54
|
-
|
|
55
26
|
return jobs.map((j: any) => ({
|
|
56
27
|
job_name: j.jobName || '',
|
|
57
28
|
salary: j.salaryDesc || '',
|