@jackwener/opencli 0.7.9 → 0.7.10

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 (43) hide show
  1. package/dist/cli-manifest.json +7 -88
  2. package/dist/clis/twitter/bookmarks.js +171 -0
  3. package/dist/clis/twitter/delete.js +0 -1
  4. package/dist/clis/twitter/followers.js +5 -16
  5. package/dist/clis/twitter/following.js +3 -4
  6. package/dist/clis/twitter/like.js +0 -1
  7. package/dist/clis/twitter/notifications.js +17 -7
  8. package/dist/clis/twitter/search.js +14 -6
  9. package/dist/clis/twitter/trending.yaml +8 -2
  10. package/dist/main.js +0 -0
  11. package/package.json +1 -1
  12. package/src/clis/twitter/bookmarks.ts +201 -0
  13. package/src/clis/twitter/delete.ts +0 -1
  14. package/src/clis/twitter/followers.ts +5 -16
  15. package/src/clis/twitter/following.ts +3 -5
  16. package/src/clis/twitter/like.ts +0 -1
  17. package/src/clis/twitter/notifications.ts +18 -9
  18. package/src/clis/twitter/search.ts +14 -7
  19. package/src/clis/twitter/trending.yaml +8 -2
  20. package/dist/_debug.js +0 -7
  21. package/dist/browser-tab.d.ts +0 -2
  22. package/dist/browser-tab.js +0 -30
  23. package/dist/browser.d.ts +0 -105
  24. package/dist/browser.js +0 -644
  25. package/dist/clis/github/search.d.ts +0 -1
  26. package/dist/clis/github/search.js +0 -20
  27. package/dist/clis/index.d.ts +0 -27
  28. package/dist/clis/index.js +0 -41
  29. package/dist/clis/twitter/bookmarks.yaml +0 -85
  30. package/dist/clis/xiaohongshu/me.d.ts +0 -1
  31. package/dist/clis/xiaohongshu/me.js +0 -86
  32. package/dist/pipeline/_debug.d.ts +0 -1
  33. package/dist/pipeline/_debug.js +0 -7
  34. package/dist/promote.d.ts +0 -1
  35. package/dist/promote.js +0 -3
  36. package/dist/register.d.ts +0 -2
  37. package/dist/register.js +0 -2
  38. package/dist/scaffold.d.ts +0 -2
  39. package/dist/scaffold.js +0 -2
  40. package/dist/smoke.d.ts +0 -2
  41. package/dist/smoke.js +0 -2
  42. package/src/clis/twitter/bookmarks.yaml +0 -85
  43. /package/dist/{_debug.d.ts → clis/twitter/bookmarks.d.ts} +0 -0
@@ -1,27 +0,0 @@
1
- /**
2
- * Import all TypeScript CLI adapters so they self-register.
3
- *
4
- * Each TS adapter calls cli() on import, which adds itself to the global registry.
5
- */
6
- import './bilibili/search.js';
7
- import './bilibili/me.js';
8
- import './bilibili/favorite.js';
9
- import './bilibili/history.js';
10
- import './bilibili/feed.js';
11
- import './bilibili/user-videos.js';
12
- import './bilibili/ranking.js';
13
- import './bilibili/dynamic.js';
14
- import './github/search.js';
15
- import './zhihu/question.js';
16
- import './xiaohongshu/search.js';
17
- import './xiaohongshu/user.js';
18
- import './bbc/news.js';
19
- import './weibo/hot.js';
20
- import './boss/search.js';
21
- import './yahoo-finance/quote.js';
22
- import './reuters/search.js';
23
- import './smzdm/search.js';
24
- import './ctrip/search.js';
25
- import './youtube/search.js';
26
- import './twitter/search.js';
27
- import './twitter/profile.js';
@@ -1,41 +0,0 @@
1
- /**
2
- * Import all TypeScript CLI adapters so they self-register.
3
- *
4
- * Each TS adapter calls cli() on import, which adds itself to the global registry.
5
- */
6
- // bilibili
7
- import './bilibili/search.js';
8
- import './bilibili/me.js';
9
- import './bilibili/favorite.js';
10
- import './bilibili/history.js';
11
- import './bilibili/feed.js';
12
- import './bilibili/user-videos.js';
13
- import './bilibili/ranking.js';
14
- import './bilibili/dynamic.js';
15
- // github
16
- import './github/search.js';
17
- // zhihu
18
- import './zhihu/question.js';
19
- // xiaohongshu
20
- import './xiaohongshu/search.js';
21
- import './xiaohongshu/user.js';
22
- // bbc
23
- import './bbc/news.js';
24
- // weibo
25
- import './weibo/hot.js';
26
- // boss
27
- import './boss/search.js';
28
- // yahoo-finance
29
- import './yahoo-finance/quote.js';
30
- // reuters
31
- import './reuters/search.js';
32
- // smzdm
33
- import './smzdm/search.js';
34
- // ctrip
35
- import './ctrip/search.js';
36
- // youtube
37
- import './youtube/search.js';
38
- // twitter
39
- import './twitter/search.js';
40
- import './twitter/profile.js';
41
- // reddit
@@ -1,85 +0,0 @@
1
- site: twitter
2
- name: bookmarks
3
- description: 获取 Twitter 书签列表
4
- domain: x.com
5
- browser: true
6
-
7
- args:
8
- limit:
9
- type: int
10
- default: 20
11
- description: Number of bookmarks to return (default 20)
12
-
13
- pipeline:
14
- - navigate: https://x.com/i/bookmarks
15
- - wait: 2
16
- - evaluate: |
17
- (async () => {
18
- const ct0 = document.cookie.split(';').map(c=>c.trim()).find(c=>c.startsWith('ct0='))?.split('=')[1];
19
- if (!ct0) throw new Error('No ct0 cookie. Hint: Not logged into x.com.');
20
- const bearer = decodeURIComponent('AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA');
21
- const _h = {'Authorization':'Bearer '+bearer, 'X-Csrf-Token':ct0, 'X-Twitter-Auth-Type':'OAuth2Session', 'X-Twitter-Active-User':'yes'};
22
-
23
- const count = Math.min(${{ args.limit }}, 100);
24
- const variables = JSON.stringify({count, includePromotedContent: false});
25
- const features = JSON.stringify({
26
- rweb_video_screen_enabled: false, profile_label_improvements_pcf_label_in_post_enabled: true,
27
- responsive_web_profile_redirect_enabled: false, rweb_tipjar_consumption_enabled: false,
28
- verified_phone_label_enabled: false, creator_subscriptions_tweet_preview_api_enabled: true,
29
- responsive_web_graphql_timeline_navigation_enabled: true,
30
- responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
31
- premium_content_api_read_enabled: false, communities_web_enable_tweet_community_results_fetch: true,
32
- c9s_tweet_anatomy_moderator_badge_enabled: true,
33
- articles_preview_enabled: true, responsive_web_edit_tweet_api_enabled: true,
34
- graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
35
- view_counts_everywhere_api_enabled: true, longform_notetweets_consumption_enabled: true,
36
- responsive_web_twitter_article_tweet_consumption_enabled: true,
37
- tweet_awards_web_tipping_enabled: false,
38
- content_disclosure_indicator_enabled: true, content_disclosure_ai_generated_indicator_enabled: true,
39
- freedom_of_speech_not_reach_fetch_enabled: true, standardized_nudges_misinfo: true,
40
- tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
41
- longform_notetweets_rich_text_read_enabled: true, longform_notetweets_inline_media_enabled: false,
42
- responsive_web_enhance_cards_enabled: false
43
- });
44
- const url = '/i/api/graphql/Fy0QMy4q_aZCpkO0PnyLYw/Bookmarks?variables=' + encodeURIComponent(variables) + '&features=' + encodeURIComponent(features);
45
- const resp = await fetch(url, {headers: _h, credentials: 'include'});
46
- if (!resp.ok) throw new Error('HTTP ' + resp.status + '. Hint: queryId may have changed.');
47
- const d = await resp.json();
48
-
49
- const instructions = d.data?.bookmark_timeline_v2?.timeline?.instructions || d.data?.bookmark_timeline?.timeline?.instructions || [];
50
- let tweets = [], seen = new Set();
51
- for (const inst of instructions) {
52
- for (const entry of (inst.entries || [])) {
53
- const r = entry.content?.itemContent?.tweet_results?.result;
54
- if (!r) continue;
55
- const tw = r.tweet || r;
56
- const l = tw.legacy || {};
57
- if (!tw.rest_id || seen.has(tw.rest_id)) continue;
58
- seen.add(tw.rest_id);
59
- const u = tw.core?.user_results?.result;
60
- const nt = tw.note_tweet?.note_tweet_results?.result?.text;
61
- const screenName = u?.legacy?.screen_name || u?.core?.screen_name;
62
- tweets.push({
63
- id: tw.rest_id,
64
- author: screenName,
65
- name: u?.legacy?.name || u?.core?.name,
66
- url: 'https://x.com/' + (screenName || '_') + '/status/' + tw.rest_id,
67
- text: nt || l.full_text || '',
68
- likes: l.favorite_count,
69
- retweets: l.retweet_count,
70
- created_at: l.created_at
71
- });
72
- }
73
- }
74
- return tweets;
75
- })()
76
-
77
- - map:
78
- author: ${{ item.author }}
79
- text: ${{ item.text }}
80
- likes: ${{ item.likes }}
81
- url: ${{ item.url }}
82
-
83
- - limit: ${{ args.limit }}
84
-
85
- columns: [author, text, likes, url]
@@ -1 +0,0 @@
1
- export {};
@@ -1,86 +0,0 @@
1
- /**
2
- * Xiaohongshu me — read self profile info.
3
- *
4
- * Two-step navigation:
5
- * 1. /explore → get user_id from Pinia user store
6
- * 2. /user/profile/{user_id} → poll until userPageData loads, read full profile
7
- */
8
- import { cli, Strategy } from '../../registry.js';
9
- cli({
10
- site: 'xiaohongshu',
11
- name: 'me',
12
- description: '我的小红书个人信息',
13
- domain: 'www.xiaohongshu.com',
14
- strategy: Strategy.COOKIE,
15
- args: [],
16
- columns: ['nickname', 'red_id', 'location', 'profession', 'fans', 'follows', 'likes_collected', 'notes'],
17
- func: async (page) => {
18
- // Step 1: Navigate to /explore to get user_id
19
- await page.goto('https://www.xiaohongshu.com/explore');
20
- await page.wait(2);
21
- const userId = await page.evaluate(`
22
- (() => {
23
- const app = document.querySelector('#app')?.__vue_app__;
24
- const pinia = app?.config?.globalProperties?.$pinia;
25
- const store = pinia?._s?.get('user');
26
- const u = store?.$state?.userInfo || {};
27
- return u.user_id || u.userId || '';
28
- })()
29
- `);
30
- if (!userId)
31
- return [{ error: 'Not logged in or user_id not found' }];
32
- // Step 2: Navigate to real profile page for full data
33
- await page.goto(`https://www.xiaohongshu.com/user/profile/${userId}`);
34
- await page.wait(3);
35
- const data = await page.evaluate(`
36
- (async () => {
37
- // Poll for userPageData to be populated (profile page loads async)
38
- const deadline = Date.now() + 8000;
39
- let pd = null;
40
- while (Date.now() < deadline) {
41
- const app = document.querySelector('#app')?.__vue_app__;
42
- const pinia = app?.config?.globalProperties?.$pinia;
43
- const store = pinia?._s?.get('user');
44
- pd = store?.$state?.userPageData;
45
- if (pd?.interactions?.length > 0) break;
46
- await new Promise(r => setTimeout(r, 500));
47
- }
48
-
49
- if (!pd?.interactions?.length) {
50
- return { error: 'Profile data did not load' };
51
- }
52
-
53
- const basic = pd.basicInfo || {};
54
- const interactions = pd.interactions || [];
55
- const tags = pd.tags || [];
56
-
57
- const getCount = (type) => {
58
- const item = interactions.find(i => i.type === type);
59
- return item ? item.count : '0';
60
- };
61
- const getTag = (tagType) => {
62
- const item = tags.find(t => t.tagType === tagType);
63
- return item ? item.name : '';
64
- };
65
-
66
- const app2 = document.querySelector('#app')?.__vue_app__;
67
- const store2 = app2?.config?.globalProperties?.$pinia?._s?.get('user');
68
- const noteCount = (store2?.$state?.notes || []).length;
69
-
70
- return {
71
- nickname: basic.nickname || '',
72
- red_id: basic.redId || '',
73
- location: getTag('location') || basic.ipLocation || '',
74
- profession: getTag('profession') || '',
75
- fans: getCount('fans'),
76
- follows: getCount('follows'),
77
- likes_collected: getCount('interaction'),
78
- notes: noteCount,
79
- };
80
- })()
81
- `);
82
- if (!data || data.error)
83
- return [];
84
- return [data];
85
- },
86
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,7 +0,0 @@
1
- import { render, evalExpr } from './pipeline/template.js';
2
- const ctx = { item: { first: 'X', second: 'Y' } };
3
- console.log('evalExpr item.first:', JSON.stringify(evalExpr('item.first', ctx)));
4
- console.log('evalExpr item.second:', JSON.stringify(evalExpr('item.second', ctx)));
5
- const template = '$' + '{{ item.first }}-$' + '{{ item.second }}';
6
- console.log('template:', JSON.stringify(template));
7
- console.log('render result:', JSON.stringify(render(template, ctx)));
package/dist/promote.d.ts DELETED
@@ -1 +0,0 @@
1
- export declare function promoteCandidate(opts: any): any;
package/dist/promote.js DELETED
@@ -1,3 +0,0 @@
1
- /** Promote verified drafts. */
2
- import { registerCandidates } from './register.js';
3
- export function promoteCandidate(opts) { return registerCandidates(opts); }
@@ -1,2 +0,0 @@
1
- /** Register candidates, promote, scaffold, generate — stubs with exports. */
2
- export declare function registerCandidates(opts: any): any;
package/dist/register.js DELETED
@@ -1,2 +0,0 @@
1
- /** Register candidates, promote, scaffold, generate — stubs with exports. */
2
- export function registerCandidates(opts) { return { ok: true, count: 0 }; }
@@ -1,2 +0,0 @@
1
- /** Scaffold a draft CLI from endpoint evidence. */
2
- export declare function scaffoldCli(opts: any): any;
package/dist/scaffold.js DELETED
@@ -1,2 +0,0 @@
1
- /** Scaffold a draft CLI from endpoint evidence. */
2
- export function scaffoldCli(opts) { return { ok: true }; }
package/dist/smoke.d.ts DELETED
@@ -1,2 +0,0 @@
1
- /** Smoke testing, verification, register, promote, explore, synthesize, scaffold, generate — stubs. */
2
- export declare function runSmoke(cmd: any, page: any, args?: any): Promise<any>;
package/dist/smoke.js DELETED
@@ -1,2 +0,0 @@
1
- /** Smoke testing, verification, register, promote, explore, synthesize, scaffold, generate — stubs. */
2
- export async function runSmoke(cmd, page, args) { return { ok: true, result: null }; }
@@ -1,85 +0,0 @@
1
- site: twitter
2
- name: bookmarks
3
- description: 获取 Twitter 书签列表
4
- domain: x.com
5
- browser: true
6
-
7
- args:
8
- limit:
9
- type: int
10
- default: 20
11
- description: Number of bookmarks to return (default 20)
12
-
13
- pipeline:
14
- - navigate: https://x.com/i/bookmarks
15
- - wait: 2
16
- - evaluate: |
17
- (async () => {
18
- const ct0 = document.cookie.split(';').map(c=>c.trim()).find(c=>c.startsWith('ct0='))?.split('=')[1];
19
- if (!ct0) throw new Error('No ct0 cookie. Hint: Not logged into x.com.');
20
- const bearer = decodeURIComponent('AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA');
21
- const _h = {'Authorization':'Bearer '+bearer, 'X-Csrf-Token':ct0, 'X-Twitter-Auth-Type':'OAuth2Session', 'X-Twitter-Active-User':'yes'};
22
-
23
- const count = Math.min(${{ args.limit }}, 100);
24
- const variables = JSON.stringify({count, includePromotedContent: false});
25
- const features = JSON.stringify({
26
- rweb_video_screen_enabled: false, profile_label_improvements_pcf_label_in_post_enabled: true,
27
- responsive_web_profile_redirect_enabled: false, rweb_tipjar_consumption_enabled: false,
28
- verified_phone_label_enabled: false, creator_subscriptions_tweet_preview_api_enabled: true,
29
- responsive_web_graphql_timeline_navigation_enabled: true,
30
- responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
31
- premium_content_api_read_enabled: false, communities_web_enable_tweet_community_results_fetch: true,
32
- c9s_tweet_anatomy_moderator_badge_enabled: true,
33
- articles_preview_enabled: true, responsive_web_edit_tweet_api_enabled: true,
34
- graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
35
- view_counts_everywhere_api_enabled: true, longform_notetweets_consumption_enabled: true,
36
- responsive_web_twitter_article_tweet_consumption_enabled: true,
37
- tweet_awards_web_tipping_enabled: false,
38
- content_disclosure_indicator_enabled: true, content_disclosure_ai_generated_indicator_enabled: true,
39
- freedom_of_speech_not_reach_fetch_enabled: true, standardized_nudges_misinfo: true,
40
- tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
41
- longform_notetweets_rich_text_read_enabled: true, longform_notetweets_inline_media_enabled: false,
42
- responsive_web_enhance_cards_enabled: false
43
- });
44
- const url = '/i/api/graphql/Fy0QMy4q_aZCpkO0PnyLYw/Bookmarks?variables=' + encodeURIComponent(variables) + '&features=' + encodeURIComponent(features);
45
- const resp = await fetch(url, {headers: _h, credentials: 'include'});
46
- if (!resp.ok) throw new Error('HTTP ' + resp.status + '. Hint: queryId may have changed.');
47
- const d = await resp.json();
48
-
49
- const instructions = d.data?.bookmark_timeline_v2?.timeline?.instructions || d.data?.bookmark_timeline?.timeline?.instructions || [];
50
- let tweets = [], seen = new Set();
51
- for (const inst of instructions) {
52
- for (const entry of (inst.entries || [])) {
53
- const r = entry.content?.itemContent?.tweet_results?.result;
54
- if (!r) continue;
55
- const tw = r.tweet || r;
56
- const l = tw.legacy || {};
57
- if (!tw.rest_id || seen.has(tw.rest_id)) continue;
58
- seen.add(tw.rest_id);
59
- const u = tw.core?.user_results?.result;
60
- const nt = tw.note_tweet?.note_tweet_results?.result?.text;
61
- const screenName = u?.legacy?.screen_name || u?.core?.screen_name;
62
- tweets.push({
63
- id: tw.rest_id,
64
- author: screenName,
65
- name: u?.legacy?.name || u?.core?.name,
66
- url: 'https://x.com/' + (screenName || '_') + '/status/' + tw.rest_id,
67
- text: nt || l.full_text || '',
68
- likes: l.favorite_count,
69
- retweets: l.retweet_count,
70
- created_at: l.created_at
71
- });
72
- }
73
- }
74
- return tweets;
75
- })()
76
-
77
- - map:
78
- author: ${{ item.author }}
79
- text: ${{ item.text }}
80
- likes: ${{ item.likes }}
81
- url: ${{ item.url }}
82
-
83
- - limit: ${{ args.limit }}
84
-
85
- columns: [author, text, likes, url]