@jackwener/opencli 1.7.3 → 1.7.5

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 (197) hide show
  1. package/README.md +81 -59
  2. package/README.zh-CN.md +93 -67
  3. package/cli-manifest.json +5015 -2975
  4. package/clis/antigravity/serve.js +71 -25
  5. package/clis/baidu-scholar/search.js +87 -0
  6. package/clis/baidu-scholar/search.test.js +23 -0
  7. package/clis/bilibili/favorite.js +18 -13
  8. package/clis/binance/depth.js +3 -4
  9. package/clis/boss/utils.js +2 -3
  10. package/clis/chatgpt-app/ax.js +6 -3
  11. package/clis/deepseek/ask.js +74 -0
  12. package/clis/deepseek/history.js +25 -0
  13. package/clis/deepseek/new.js +20 -0
  14. package/clis/deepseek/read.js +22 -0
  15. package/clis/deepseek/status.js +24 -0
  16. package/clis/deepseek/utils.js +208 -0
  17. package/clis/douban/search.js +1 -0
  18. package/clis/douban/search.test.js +11 -0
  19. package/clis/douban/subject.js +20 -93
  20. package/clis/douban/subject.test.js +11 -0
  21. package/clis/douban/utils.js +250 -8
  22. package/clis/douban/utils.test.js +179 -4
  23. package/clis/doubao/utils.js +319 -130
  24. package/clis/doubao/utils.test.js +241 -2
  25. package/clis/eastmoney/_secid.js +78 -0
  26. package/clis/eastmoney/announcement.js +52 -0
  27. package/clis/eastmoney/convertible.js +73 -0
  28. package/clis/eastmoney/etf.js +65 -0
  29. package/clis/eastmoney/holders.js +78 -0
  30. package/clis/eastmoney/hot-rank.js +50 -0
  31. package/clis/eastmoney/hot-rank.test.js +59 -0
  32. package/clis/eastmoney/index-board.js +96 -0
  33. package/clis/eastmoney/kline.js +87 -0
  34. package/clis/eastmoney/kuaixun.js +54 -0
  35. package/clis/eastmoney/longhu.js +67 -0
  36. package/clis/eastmoney/money-flow.js +78 -0
  37. package/clis/eastmoney/northbound.js +57 -0
  38. package/clis/eastmoney/quote.js +107 -0
  39. package/clis/eastmoney/rank.js +94 -0
  40. package/clis/eastmoney/sectors.js +76 -0
  41. package/clis/google-scholar/search.js +58 -0
  42. package/clis/google-scholar/search.test.js +23 -0
  43. package/clis/gov-law/commands.test.js +39 -0
  44. package/clis/gov-law/recent.js +22 -0
  45. package/clis/gov-law/search.js +41 -0
  46. package/clis/gov-law/shared.js +51 -0
  47. package/clis/gov-policy/commands.test.js +27 -0
  48. package/clis/gov-policy/recent.js +47 -0
  49. package/clis/gov-policy/search.js +48 -0
  50. package/clis/grok/image.test.ts +107 -0
  51. package/clis/grok/image.ts +356 -0
  52. package/clis/nowcoder/companies.js +23 -0
  53. package/clis/nowcoder/creators.js +27 -0
  54. package/clis/nowcoder/detail.js +61 -0
  55. package/clis/nowcoder/experience.js +36 -0
  56. package/clis/nowcoder/hot.js +24 -0
  57. package/clis/nowcoder/jobs.js +21 -0
  58. package/clis/nowcoder/notifications.js +29 -0
  59. package/clis/nowcoder/papers.js +40 -0
  60. package/clis/nowcoder/practice.js +37 -0
  61. package/clis/nowcoder/recommend.js +30 -0
  62. package/clis/nowcoder/referral.js +39 -0
  63. package/clis/nowcoder/salary.js +40 -0
  64. package/clis/nowcoder/search.js +49 -0
  65. package/clis/nowcoder/suggest.js +33 -0
  66. package/clis/nowcoder/topics.js +27 -0
  67. package/clis/nowcoder/trending.js +25 -0
  68. package/clis/tdx/hot-rank.js +47 -0
  69. package/clis/tdx/hot-rank.test.js +59 -0
  70. package/clis/ths/hot-rank.js +49 -0
  71. package/clis/ths/hot-rank.test.js +64 -0
  72. package/clis/twitter/bookmarks.js +2 -1
  73. package/clis/twitter/list-add.js +337 -0
  74. package/clis/twitter/list-add.test.js +15 -0
  75. package/clis/twitter/list-remove.js +297 -0
  76. package/clis/twitter/list-remove.test.js +14 -0
  77. package/clis/twitter/list-tweets.js +185 -0
  78. package/clis/twitter/list-tweets.test.js +108 -0
  79. package/clis/twitter/lists.js +134 -47
  80. package/clis/twitter/lists.test.js +105 -38
  81. package/clis/uiverse/_shared.js +368 -0
  82. package/clis/uiverse/_shared.test.js +55 -0
  83. package/clis/uiverse/code.js +47 -0
  84. package/clis/uiverse/preview.js +71 -0
  85. package/clis/wanfang/search.js +66 -0
  86. package/clis/wanfang/search.test.js +23 -0
  87. package/clis/web/read.js +1 -1
  88. package/clis/weixin/download.js +3 -2
  89. package/clis/xiaohongshu/comments.js +2 -2
  90. package/clis/xiaohongshu/comments.test.js +46 -25
  91. package/clis/xiaohongshu/download.js +6 -7
  92. package/clis/xiaohongshu/download.test.js +17 -5
  93. package/clis/xiaohongshu/note-helpers.js +46 -12
  94. package/clis/xiaohongshu/note.js +3 -5
  95. package/clis/xiaohongshu/note.test.js +52 -25
  96. package/clis/xiaohongshu/publish.js +149 -28
  97. package/clis/xiaohongshu/publish.test.js +319 -6
  98. package/clis/xiaoyuzhou/auth.js +303 -0
  99. package/clis/xiaoyuzhou/auth.test.js +124 -0
  100. package/clis/xiaoyuzhou/download.js +53 -0
  101. package/clis/xiaoyuzhou/download.test.js +135 -0
  102. package/clis/xiaoyuzhou/episode.js +9 -4
  103. package/clis/xiaoyuzhou/podcast-episodes.js +15 -11
  104. package/clis/xiaoyuzhou/podcast.js +9 -4
  105. package/clis/xiaoyuzhou/transcript.js +76 -0
  106. package/clis/xiaoyuzhou/transcript.test.js +195 -0
  107. package/clis/xiaoyuzhou/utils.js +0 -40
  108. package/clis/xiaoyuzhou/utils.test.js +15 -75
  109. package/clis/youtube/feed.js +120 -0
  110. package/clis/youtube/history.js +118 -0
  111. package/clis/youtube/like.js +62 -0
  112. package/clis/youtube/playlist.js +97 -0
  113. package/clis/youtube/subscribe.js +71 -0
  114. package/clis/youtube/subscriptions.js +57 -0
  115. package/clis/youtube/unlike.js +62 -0
  116. package/clis/youtube/unsubscribe.js +71 -0
  117. package/clis/youtube/utils.js +122 -0
  118. package/clis/youtube/utils.test.js +32 -1
  119. package/clis/youtube/watch-later.js +76 -0
  120. package/clis/zsxq/dynamics.js +1 -1
  121. package/clis/zsxq/utils.js +6 -3
  122. package/clis/zsxq/utils.test.js +31 -0
  123. package/dist/src/browser/base-page.d.ts +1 -1
  124. package/dist/src/browser/base-page.js +25 -5
  125. package/dist/src/browser/bridge.d.ts +3 -0
  126. package/dist/src/browser/bridge.js +52 -15
  127. package/dist/src/browser/cdp.js +2 -1
  128. package/dist/src/browser/daemon-client.d.ts +7 -4
  129. package/dist/src/browser/daemon-client.js +6 -1
  130. package/dist/src/browser/daemon-client.test.js +40 -1
  131. package/dist/src/browser/dom-snapshot.js +20 -3
  132. package/dist/src/browser/page.d.ts +18 -5
  133. package/dist/src/browser/page.js +96 -15
  134. package/dist/src/browser/page.test.js +158 -1
  135. package/dist/src/browser/target-errors.d.ts +23 -0
  136. package/dist/src/browser/target-errors.js +29 -0
  137. package/dist/src/browser/target-errors.test.js +61 -0
  138. package/dist/src/browser/target-resolver.d.ts +57 -0
  139. package/dist/src/browser/target-resolver.js +298 -0
  140. package/dist/src/browser/target-resolver.test.js +43 -0
  141. package/dist/src/browser.test.js +38 -1
  142. package/dist/src/cli.js +272 -187
  143. package/dist/src/cli.test.js +167 -90
  144. package/dist/src/commanderAdapter.d.ts +0 -1
  145. package/dist/src/commanderAdapter.js +2 -16
  146. package/dist/src/commanderAdapter.test.js +1 -1
  147. package/dist/src/commands/daemon.d.ts +4 -2
  148. package/dist/src/commands/daemon.js +22 -2
  149. package/dist/src/commands/daemon.test.js +65 -2
  150. package/dist/src/completion-shared.js +2 -5
  151. package/dist/src/daemon.js +10 -0
  152. package/dist/src/doctor.d.ts +1 -0
  153. package/dist/src/doctor.js +32 -9
  154. package/dist/src/doctor.test.js +28 -12
  155. package/dist/src/download/article-download.d.ts +1 -0
  156. package/dist/src/download/article-download.js +3 -0
  157. package/dist/src/download/article-download.test.js +39 -0
  158. package/dist/src/external-clis.yaml +2 -2
  159. package/dist/src/logger.d.ts +2 -2
  160. package/dist/src/logger.js +3 -3
  161. package/dist/src/output.js +1 -5
  162. package/dist/src/output.test.js +0 -21
  163. package/dist/src/pipeline/steps/transform.js +1 -1
  164. package/dist/src/pipeline/template.d.ts +1 -0
  165. package/dist/src/pipeline/template.js +11 -3
  166. package/dist/src/pipeline/template.test.js +3 -0
  167. package/dist/src/pipeline/transform.test.js +14 -0
  168. package/dist/src/plugin.d.ts +8 -9
  169. package/dist/src/plugin.js +24 -28
  170. package/dist/src/plugin.test.js +16 -60
  171. package/dist/src/registry.d.ts +1 -0
  172. package/dist/src/registry.js +3 -2
  173. package/dist/src/registry.test.js +22 -0
  174. package/dist/src/types.d.ts +15 -6
  175. package/package.json +1 -1
  176. package/clis/twitter/lists-parser.js +0 -77
  177. package/clis/twitter/lists.d.ts +0 -5
  178. package/dist/src/cascade.d.ts +0 -46
  179. package/dist/src/cascade.js +0 -135
  180. package/dist/src/explore.d.ts +0 -99
  181. package/dist/src/explore.js +0 -402
  182. package/dist/src/generate-verified.d.ts +0 -105
  183. package/dist/src/generate-verified.js +0 -696
  184. package/dist/src/generate-verified.test.js +0 -925
  185. package/dist/src/generate.d.ts +0 -46
  186. package/dist/src/generate.js +0 -117
  187. package/dist/src/record.d.ts +0 -96
  188. package/dist/src/record.js +0 -657
  189. package/dist/src/record.test.js +0 -293
  190. package/dist/src/skill-generate.d.ts +0 -30
  191. package/dist/src/skill-generate.js +0 -75
  192. package/dist/src/skill-generate.test.js +0 -173
  193. package/dist/src/synthesize.d.ts +0 -97
  194. package/dist/src/synthesize.js +0 -208
  195. /package/dist/src/{generate-verified.test.d.ts → browser/target-errors.test.d.ts} +0 -0
  196. /package/dist/src/{record.test.d.ts → browser/target-resolver.test.d.ts} +0 -0
  197. /package/dist/src/{skill-generate.test.d.ts → download/article-download.test.d.ts} +0 -0
@@ -1,208 +0,0 @@
1
- /**
2
- * Synthesize candidate CLIs from explore artifacts.
3
- * Generates evaluate-based pipelines (matching hand-written adapter patterns).
4
- */
5
- import * as fs from 'node:fs';
6
- import * as path from 'node:path';
7
- import { VOLATILE_PARAMS, SEARCH_PARAMS, LIMIT_PARAMS, PAGINATION_PARAMS } from './constants.js';
8
- export function synthesizeFromExplore(target, opts = {}) {
9
- const exploreDir = resolveExploreDir(target);
10
- const bundle = loadExploreBundle(exploreDir);
11
- const targetDir = opts.outDir ?? path.join(exploreDir, 'candidates');
12
- fs.mkdirSync(targetDir, { recursive: true });
13
- const site = bundle.manifest.site;
14
- const capabilities = (bundle.capabilities ?? [])
15
- .slice(0, opts.top ?? 3);
16
- const candidates = [];
17
- for (const cap of capabilities) {
18
- const endpoint = chooseEndpoint(cap, bundle.endpoints);
19
- if (!endpoint)
20
- continue;
21
- const candidate = buildCandidateYaml(site, bundle.manifest, cap, endpoint);
22
- const filePath = path.join(targetDir, `${candidate.name}.json`);
23
- fs.writeFileSync(filePath, JSON.stringify(candidate.yaml, null, 2));
24
- candidates.push({ name: candidate.name, path: filePath, strategy: cap.strategy });
25
- }
26
- const index = { site, target_url: bundle.manifest.target_url, generated_from: exploreDir, candidate_count: candidates.length, candidates };
27
- fs.writeFileSync(path.join(targetDir, 'candidates.json'), JSON.stringify(index, null, 2));
28
- return { site, explore_dir: exploreDir, out_dir: targetDir, candidate_count: candidates.length, candidates };
29
- }
30
- export function renderSynthesizeSummary(result) {
31
- const lines = ['opencli synthesize: OK', `Site: ${result.site}`, `Source: ${result.explore_dir}`, `Candidates: ${result.candidate_count}`];
32
- for (const c of result.candidates ?? [])
33
- lines.push(` • ${c.name} (${c.strategy}) → ${c.path}`);
34
- return lines.join('\n');
35
- }
36
- export function resolveExploreDir(target) {
37
- if (fs.existsSync(target))
38
- return target;
39
- const candidate = path.join('.opencli', 'explore', target);
40
- if (fs.existsSync(candidate))
41
- return candidate;
42
- throw new Error(`Explore directory not found: ${target}`);
43
- }
44
- export function loadExploreBundle(exploreDir) {
45
- return {
46
- manifest: JSON.parse(fs.readFileSync(path.join(exploreDir, 'manifest.json'), 'utf-8')),
47
- endpoints: JSON.parse(fs.readFileSync(path.join(exploreDir, 'endpoints.json'), 'utf-8')),
48
- capabilities: JSON.parse(fs.readFileSync(path.join(exploreDir, 'capabilities.json'), 'utf-8')),
49
- auth: JSON.parse(fs.readFileSync(path.join(exploreDir, 'auth.json'), 'utf-8')),
50
- };
51
- }
52
- function chooseEndpoint(cap, endpoints) {
53
- if (!endpoints.length)
54
- return null;
55
- // Match by endpoint pattern from capability
56
- if (cap.endpoint) {
57
- const endpointPattern = cap.endpoint;
58
- const match = endpoints.find((endpoint) => endpoint.pattern === endpointPattern || endpoint.url?.includes(endpointPattern));
59
- if (match)
60
- return match;
61
- }
62
- // Fallback: prefer endpoint with most data (item count + detected fields)
63
- return [...endpoints].sort((a, b) => {
64
- const aKey = (a.itemCount ?? 0) * 10 + Object.keys(a.detectedFields ?? {}).length;
65
- const bKey = (b.itemCount ?? 0) * 10 + Object.keys(b.detectedFields ?? {}).length;
66
- return bKey - aKey;
67
- })[0];
68
- }
69
- // ── URL templating ─────────────────────────────────────────────────────────
70
- function buildTemplatedUrl(rawUrl, cap, _endpoint) {
71
- try {
72
- const u = new URL(rawUrl);
73
- const base = `${u.protocol}//${u.host}${u.pathname}`;
74
- const params = [];
75
- const hasKeyword = cap.recommendedArgs?.some((arg) => arg.name === 'keyword');
76
- u.searchParams.forEach((v, k) => {
77
- if (VOLATILE_PARAMS.has(k))
78
- return;
79
- if (hasKeyword && SEARCH_PARAMS.has(k))
80
- params.push([k, '${{ args.keyword }}']);
81
- else if (LIMIT_PARAMS.has(k))
82
- params.push([k, '${{ args.limit | default(20) }}']);
83
- else if (PAGINATION_PARAMS.has(k))
84
- params.push([k, '${{ args.page | default(1) }}']);
85
- else
86
- params.push([k, v]);
87
- });
88
- return params.length ? base + '?' + params.map(([k, v]) => `${k}=${v}`).join('&') : base;
89
- }
90
- catch {
91
- return rawUrl;
92
- }
93
- }
94
- /**
95
- * Build inline evaluate script for browser-based fetch+parse.
96
- * Follows patterns from bilibili/hot.ts and twitter/trending.ts.
97
- */
98
- function buildEvaluateScript(url, itemPath, endpoint) {
99
- const pathChain = itemPath.split('.').map((p) => `?.${p}`).join('');
100
- const detectedFields = endpoint?.detectedFields ?? {};
101
- const hasFields = Object.keys(detectedFields).length > 0;
102
- let mapCode = '';
103
- if (hasFields) {
104
- const mappings = Object.entries(detectedFields)
105
- .map(([role, field]) => ` ${role}: item${String(field).split('.').map(p => `?.${p}`).join('')}`)
106
- .join(',\n');
107
- mapCode = `.map((item) => ({\n${mappings}\n }))`;
108
- }
109
- return [
110
- '(async () => {',
111
- ` const res = await fetch(${JSON.stringify(url)}, {`,
112
- ` credentials: 'include'`,
113
- ' });',
114
- ' const data = await res.json();',
115
- ` return (data${pathChain} || [])${mapCode};`,
116
- '})()\n',
117
- ].join('\n');
118
- }
119
- // ── Pipeline generation ────────────────────────────────────────────────────
120
- function buildCandidateYaml(site, manifest, cap, endpoint) {
121
- const needsBrowser = cap.strategy !== 'public';
122
- const pipeline = [];
123
- const templatedUrl = buildTemplatedUrl(endpoint?.url ?? manifest.target_url, cap, endpoint);
124
- let domain = '';
125
- try {
126
- domain = new URL(manifest.target_url).hostname;
127
- }
128
- catch { }
129
- if (cap.strategy === 'store-action' && cap.storeHint) {
130
- // Store Action: navigate + wait + tap (declarative, clean)
131
- pipeline.push({ navigate: manifest.target_url });
132
- pipeline.push({ wait: 3 });
133
- const tapStep = {
134
- store: cap.storeHint.store,
135
- action: cap.storeHint.action,
136
- timeout: 8,
137
- };
138
- // Infer capture pattern from endpoint URL
139
- if (endpoint?.url) {
140
- try {
141
- const epUrl = new URL(endpoint.url);
142
- const pathParts = epUrl.pathname.split('/').filter((p) => p);
143
- // Use last meaningful path segment as capture pattern
144
- const capturePart = pathParts.filter((p) => !p.match(/^v\d+$/)).pop();
145
- if (capturePart)
146
- tapStep.capture = capturePart;
147
- }
148
- catch { }
149
- }
150
- if (cap.itemPath)
151
- tapStep.select = cap.itemPath;
152
- pipeline.push({ tap: tapStep });
153
- }
154
- else if (needsBrowser) {
155
- // Browser-based: navigate + evaluate (like bilibili/hot, twitter/trending)
156
- pipeline.push({ navigate: manifest.target_url });
157
- const itemPath = cap.itemPath ?? 'data.data.list';
158
- pipeline.push({ evaluate: buildEvaluateScript(templatedUrl, itemPath, endpoint) });
159
- }
160
- else {
161
- // Public API: direct fetch (like hackernews/top)
162
- pipeline.push({ fetch: { url: templatedUrl } });
163
- if (cap.itemPath)
164
- pipeline.push({ select: cap.itemPath });
165
- }
166
- // Map fields
167
- const mapStep = {};
168
- const columns = cap.recommendedColumns ?? ['title', 'url'];
169
- if (!cap.recommendedArgs?.some((arg) => arg.name === 'keyword'))
170
- mapStep['rank'] = '${{ index + 1 }}';
171
- const detectedFields = endpoint?.detectedFields ?? {};
172
- for (const col of columns) {
173
- const fieldPath = detectedFields[col];
174
- mapStep[col] = fieldPath ? `\${{ item.${fieldPath} }}` : `\${{ item.${col} }}`;
175
- }
176
- pipeline.push({ map: mapStep });
177
- pipeline.push({ limit: '${{ args.limit | default(20) }}' });
178
- // Args
179
- const argsDef = {};
180
- for (const arg of cap.recommendedArgs ?? []) {
181
- const def = { type: arg.type ?? 'str' };
182
- if (arg.required)
183
- def.required = true;
184
- if (arg.default != null)
185
- def.default = arg.default;
186
- if (arg.name === 'keyword')
187
- def.description = 'Search keyword';
188
- else if (arg.name === 'limit')
189
- def.description = 'Number of items to return';
190
- else if (arg.name === 'page')
191
- def.description = 'Page number';
192
- argsDef[arg.name] = def;
193
- }
194
- if (!argsDef['limit'])
195
- argsDef['limit'] = { type: 'int', default: 20, description: 'Number of items to return' };
196
- return {
197
- name: cap.name,
198
- yaml: {
199
- site, name: cap.name, description: `${cap.description || site + ' ' + cap.name} (auto-generated)`,
200
- domain, strategy: cap.strategy, browser: needsBrowser,
201
- args: argsDef, pipeline, columns: Object.keys(mapStep),
202
- },
203
- };
204
- }
205
- export function buildCandidate(site, targetUrl, cap, endpoint) {
206
- const manifest = { target_url: targetUrl, final_url: targetUrl };
207
- return buildCandidateYaml(site, manifest, cap, endpoint);
208
- }