@jackwener/opencli 0.1.2 → 0.3.0

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 (72) hide show
  1. package/CLI-CREATOR.md +51 -72
  2. package/README.md +8 -5
  3. package/README.zh-CN.md +8 -5
  4. package/SKILL.md +27 -14
  5. package/dist/browser.d.ts +7 -0
  6. package/dist/browser.js +85 -2
  7. package/dist/clis/bilibili/dynamic.d.ts +1 -0
  8. package/dist/clis/bilibili/dynamic.js +33 -0
  9. package/dist/clis/bilibili/ranking.d.ts +1 -0
  10. package/dist/clis/bilibili/ranking.js +24 -0
  11. package/dist/clis/reddit/frontpage.yaml +30 -0
  12. package/dist/clis/reddit/hot.yaml +3 -2
  13. package/dist/clis/reddit/search.yaml +34 -0
  14. package/dist/clis/reddit/subreddit.yaml +39 -0
  15. package/dist/clis/twitter/bookmarks.yaml +85 -0
  16. package/dist/clis/twitter/profile.d.ts +1 -0
  17. package/dist/clis/twitter/profile.js +56 -0
  18. package/dist/clis/twitter/search.d.ts +1 -0
  19. package/dist/clis/twitter/search.js +60 -0
  20. package/dist/clis/twitter/timeline.d.ts +1 -0
  21. package/dist/clis/twitter/timeline.js +47 -0
  22. package/dist/clis/xiaohongshu/user.d.ts +1 -0
  23. package/dist/clis/xiaohongshu/user.js +40 -0
  24. package/dist/clis/xueqiu/feed.yaml +53 -0
  25. package/dist/clis/xueqiu/hot-stock.yaml +49 -0
  26. package/dist/clis/xueqiu/hot.yaml +46 -0
  27. package/dist/clis/xueqiu/search.yaml +53 -0
  28. package/dist/clis/xueqiu/stock.yaml +67 -0
  29. package/dist/clis/xueqiu/watchlist.yaml +46 -0
  30. package/dist/clis/zhihu/hot.yaml +6 -2
  31. package/dist/clis/zhihu/search.yaml +3 -1
  32. package/dist/engine.d.ts +1 -1
  33. package/dist/engine.js +9 -1
  34. package/dist/main.d.ts +1 -1
  35. package/dist/main.js +10 -3
  36. package/dist/output.d.ts +1 -1
  37. package/dist/output.js +12 -8
  38. package/dist/pipeline/steps/intercept.js +56 -29
  39. package/dist/pipeline/template.js +74 -15
  40. package/dist/pipeline/template.test.js +24 -0
  41. package/dist/types.d.ts +6 -0
  42. package/package.json +1 -1
  43. package/src/browser.ts +88 -5
  44. package/src/clis/bilibili/dynamic.ts +34 -0
  45. package/src/clis/bilibili/ranking.ts +25 -0
  46. package/src/clis/reddit/frontpage.yaml +30 -0
  47. package/src/clis/reddit/hot.yaml +3 -2
  48. package/src/clis/reddit/search.yaml +34 -0
  49. package/src/clis/reddit/subreddit.yaml +39 -0
  50. package/src/clis/twitter/bookmarks.yaml +85 -0
  51. package/src/clis/twitter/profile.ts +61 -0
  52. package/src/clis/twitter/search.ts +65 -0
  53. package/src/clis/twitter/timeline.ts +50 -0
  54. package/src/clis/xiaohongshu/user.ts +45 -0
  55. package/src/clis/xueqiu/feed.yaml +53 -0
  56. package/src/clis/xueqiu/hot-stock.yaml +49 -0
  57. package/src/clis/xueqiu/hot.yaml +46 -0
  58. package/src/clis/xueqiu/search.yaml +53 -0
  59. package/src/clis/xueqiu/stock.yaml +67 -0
  60. package/src/clis/xueqiu/watchlist.yaml +46 -0
  61. package/src/clis/zhihu/hot.yaml +6 -2
  62. package/src/clis/zhihu/search.yaml +3 -1
  63. package/src/engine.ts +10 -1
  64. package/src/main.ts +9 -3
  65. package/src/output.ts +10 -6
  66. package/src/pipeline/steps/intercept.ts +58 -28
  67. package/src/pipeline/template.test.ts +24 -0
  68. package/src/pipeline/template.ts +72 -14
  69. package/src/types.ts +3 -0
  70. package/dist/clis/index.d.ts +0 -22
  71. package/dist/clis/index.js +0 -34
  72. package/src/clis/index.ts +0 -46
@@ -17,12 +17,16 @@ pipeline:
17
17
  const res = await fetch('https://www.zhihu.com/api/v3/feed/topstory/hot-lists/total?limit=50', {
18
18
  credentials: 'include'
19
19
  });
20
- const d = await res.json();
20
+ const text = await res.text();
21
+ const d = JSON.parse(
22
+ text.replace(/("id"\s*:\s*)(\d{16,})/g, '$1"$2"')
23
+ );
21
24
  return (d?.data || []).map((item) => {
22
25
  const t = item.target || {};
26
+ const questionId = t.id == null ? '' : String(t.id);
23
27
  return {
24
28
  title: t.title,
25
- url: 'https://www.zhihu.com/question/' + t.id,
29
+ url: 'https://www.zhihu.com/question/' + questionId,
26
30
  answer_count: t.answer_count,
27
31
  follower_count: t.follower_count,
28
32
  heat: item.detail_text || '',
@@ -19,7 +19,9 @@ pipeline:
19
19
  - evaluate: |
20
20
  (async () => {
21
21
  const strip = (html) => (html || '').replace(/<[^>]+>/g, '').replace(/&nbsp;/g, ' ').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&').replace(/<em>/g, '').replace(/<\/em>/g, '').trim();
22
- const res = await fetch('https://www.zhihu.com/api/v4/search_v3?q=' + encodeURIComponent('${{ args.keyword }}') + '&t=general&offset=0&limit=${{ args.limit }}', {
22
+ const keyword = ${{ args.keyword | json }};
23
+ const limit = ${{ args.limit }};
24
+ const res = await fetch('https://www.zhihu.com/api/v4/search_v3?q=' + encodeURIComponent(keyword) + '&t=general&offset=0&limit=' + limit, {
23
25
  credentials: 'include'
24
26
  });
25
27
  const d = await res.json();
package/src/engine.ts CHANGED
@@ -9,7 +9,8 @@ import { type CliCommand, type Arg, Strategy, registerCommand } from './registry
9
9
  import type { IPage } from './types.js';
10
10
  import { executePipeline } from './pipeline.js';
11
11
 
12
- export function discoverClis(...dirs: string[]): void {
12
+ export async function discoverClis(...dirs: string[]): Promise<void> {
13
+ const promises: Promise<any>[] = [];
13
14
  for (const dir of dirs) {
14
15
  if (!fs.existsSync(dir)) continue;
15
16
  for (const site of fs.readdirSync(dir)) {
@@ -19,10 +20,18 @@ export function discoverClis(...dirs: string[]): void {
19
20
  const filePath = path.join(siteDir, file);
20
21
  if (file.endsWith('.yaml') || file.endsWith('.yml')) {
21
22
  registerYamlCli(filePath, site);
23
+ } else if (file.endsWith('.js')) {
24
+ // Dynamic import of compiled adapter modules
25
+ promises.push(
26
+ import(`file://${filePath}`).catch((err: any) => {
27
+ process.stderr.write(`Warning: failed to load module ${filePath}: ${err.message}\n`);
28
+ })
29
+ );
22
30
  }
23
31
  }
24
32
  }
25
33
  }
34
+ await Promise.all(promises);
26
35
  }
27
36
 
28
37
  function registerYamlCli(filePath: string, defaultSite: string): void {
package/src/main.ts CHANGED
@@ -12,7 +12,6 @@ import chalk from 'chalk';
12
12
  import { discoverClis, executeCommand } from './engine.js';
13
13
  import { type CliCommand, fullName, getRegistry, strategyLabel } from './registry.js';
14
14
  import { render as renderOutput } from './output.js';
15
- import './clis/index.js';
16
15
  import { PlaywrightMCP } from './browser.js';
17
16
  import { browserSession, DEFAULT_BROWSER_COMMAND_TIMEOUT, runWithTimeout } from './runtime.js';
18
17
 
@@ -25,7 +24,7 @@ const USER_CLIS = path.join(os.homedir(), '.opencli', 'clis');
25
24
  const pkgJsonPath = path.resolve(__dirname, '..', 'package.json');
26
25
  const PKG_VERSION = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8')).version ?? '0.0.0';
27
26
 
28
- discoverClis(BUILTIN_CLIS, USER_CLIS);
27
+ await discoverClis(BUILTIN_CLIS, USER_CLIS);
29
28
 
30
29
  const program = new Command();
31
30
  program.name('opencli').description('Make any website your CLI. Zero setup. AI-powered.').version(PKG_VERSION);
@@ -104,8 +103,15 @@ for (const [, cmd] of registry) {
104
103
  if (cmd.browser) {
105
104
  result = await browserSession(PlaywrightMCP, async (page) => runWithTimeout(executeCommand(cmd, page, kwargs, actionOpts.verbose), { timeout: cmd.timeoutSeconds ?? DEFAULT_BROWSER_COMMAND_TIMEOUT, label: fullName(cmd) }));
106
105
  } else { result = await executeCommand(cmd, null, kwargs, actionOpts.verbose); }
106
+ if (actionOpts.verbose && (!result || (Array.isArray(result) && result.length === 0))) {
107
+ console.error(chalk.yellow(`[Verbose] Warning: Command returned an empty result. If the website structural API changed or requires authentication, check the network or update the adapter.`));
108
+ }
107
109
  renderOutput(result, { fmt: actionOpts.format, columns: cmd.columns, title: `${cmd.site}/${cmd.name}`, elapsed: (Date.now() - startTime) / 1000, source: fullName(cmd) });
108
- } catch (err: any) { console.error(chalk.red(`Error: ${err.message ?? err}`)); process.exitCode = 1; }
110
+ } catch (err: any) {
111
+ if (actionOpts.verbose && err.stack) { console.error(chalk.red(err.stack)); }
112
+ else { console.error(chalk.red(`Error: ${err.message ?? err}`)); }
113
+ process.exitCode = 1;
114
+ }
109
115
  });
110
116
  }
111
117
 
package/src/output.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  /**
2
- * Output formatting: table, JSON, Markdown, CSV.
2
+ * Output formatting: table, JSON, Markdown, CSV, YAML.
3
3
  */
4
4
 
5
5
  import chalk from 'chalk';
6
6
  import Table from 'cli-table3';
7
+ import yaml from 'js-yaml';
7
8
 
8
9
  export interface RenderOptions {
9
10
  fmt?: string;
@@ -23,6 +24,7 @@ export function render(data: any, opts: RenderOptions = {}): void {
23
24
  case 'json': renderJson(data); break;
24
25
  case 'md': case 'markdown': renderMarkdown(data, opts); break;
25
26
  case 'csv': renderCsv(data, opts); break;
27
+ case 'yaml': case 'yml': renderYaml(data); break;
26
28
  default: renderTable(data, opts); break;
27
29
  }
28
30
  }
@@ -32,16 +34,14 @@ function renderTable(data: any, opts: RenderOptions): void {
32
34
  if (!rows.length) { console.log(chalk.dim('(no data)')); return; }
33
35
  const columns = opts.columns ?? Object.keys(rows[0]);
34
36
 
35
- const header = columns.map((c, i) => i === 0 ? '#' : capitalize(c));
37
+ const header = columns.map(c => capitalize(c));
36
38
  const table = new Table({
37
39
  head: header.map(h => chalk.bold(h)),
38
40
  style: { head: [], border: [] },
39
41
  wordWrap: true,
40
42
  wrapOnWordBoundary: true,
41
- colWidths: columns.map((c, i) => {
42
- if (i === 0) return 4;
43
- if (c === 'url' || c === 'description') return null as any;
44
- if (c === 'title' || c === 'name' || c === 'repo') return null as any;
43
+ colWidths: columns.map((_c, i) => {
44
+ if (i === 0) return 6;
45
45
  return null as any;
46
46
  }).filter(() => true),
47
47
  });
@@ -91,6 +91,10 @@ function renderCsv(data: any, opts: RenderOptions): void {
91
91
  }
92
92
  }
93
93
 
94
+ function renderYaml(data: any): void {
95
+ console.log(yaml.dump(data, { sortKeys: false, lineWidth: 120, noRefs: true }));
96
+ }
97
+
94
98
  function capitalize(s: string): string {
95
99
  return s.charAt(0).toUpperCase() + s.slice(1);
96
100
  }
@@ -14,7 +14,55 @@ export async function stepIntercept(page: IPage, params: any, data: any, args: R
14
14
 
15
15
  if (!capturePattern) return data;
16
16
 
17
- // Step 1: Execute the trigger action
17
+ // Step 1: Inject fetch/XHR interceptor BEFORE trigger
18
+ await page.evaluate(`
19
+ () => {
20
+ window.__opencli_intercepted = window.__opencli_intercepted || [];
21
+ const pattern = ${JSON.stringify(capturePattern)};
22
+
23
+ if (!window.__opencli_fetch_patched) {
24
+ const origFetch = window.fetch;
25
+ window.fetch = async function(...args) {
26
+ const reqUrl = typeof args[0] === 'string' ? args[0] : (args[0] && args[0].url) || '';
27
+ const response = await origFetch.apply(this, args);
28
+ setTimeout(async () => {
29
+ try {
30
+ if (reqUrl.includes(pattern)) {
31
+ const clone = response.clone();
32
+ const json = await clone.json();
33
+ window.__opencli_intercepted.push(json);
34
+ }
35
+ } catch(e) {}
36
+ }, 0);
37
+ return response;
38
+ };
39
+ window.__opencli_fetch_patched = true;
40
+ }
41
+
42
+ if (!window.__opencli_xhr_patched) {
43
+ const XHR = XMLHttpRequest.prototype;
44
+ const open = XHR.open;
45
+ const send = XHR.send;
46
+ XHR.open = function(method, url, ...args) {
47
+ this._reqUrl = url;
48
+ return open.call(this, method, url, ...args);
49
+ };
50
+ XHR.send = function(...args) {
51
+ this.addEventListener('load', function() {
52
+ try {
53
+ if (this._reqUrl && this._reqUrl.includes(pattern)) {
54
+ window.__opencli_intercepted.push(JSON.parse(this.responseText));
55
+ }
56
+ } catch(e) {}
57
+ });
58
+ return send.apply(this, args);
59
+ };
60
+ window.__opencli_xhr_patched = true;
61
+ }
62
+ }
63
+ `);
64
+
65
+ // Step 2: Execute the trigger action
18
66
  if (trigger.startsWith('navigate:')) {
19
67
  const url = render(trigger.slice('navigate:'.length), { args, data });
20
68
  await page.goto(String(url));
@@ -29,36 +77,18 @@ export async function stepIntercept(page: IPage, params: any, data: any, args: R
29
77
  await page.scroll('down');
30
78
  }
31
79
 
32
- // Step 2: Wait a bit for network requests to fire
80
+ // Step 3: Wait a bit for network requests to fire
33
81
  await page.wait(Math.min(timeout, 3));
34
82
 
35
- // Step 3: Get network requests and find matching ones
36
- const rawNetwork = await page.networkRequests(false);
37
- const matchingResponses: any[] = [];
38
-
39
- if (typeof rawNetwork === 'string') {
40
- const lines = rawNetwork.split('\n');
41
- for (const line of lines) {
42
- const match = line.match(/\[?(GET|POST)\]?\s+(\S+)\s*(?:=>|→)\s*\[?(\d+)\]?/i);
43
- if (match) {
44
- const [, , url, status] = match;
45
- if (url.includes(capturePattern) && status === '200') {
46
- try {
47
- const body = await page.evaluate(`
48
- async () => {
49
- try {
50
- const resp = await fetch(${JSON.stringify(url)}, { credentials: 'include' });
51
- if (!resp.ok) return null;
52
- return await resp.json();
53
- } catch { return null; }
54
- }
55
- `);
56
- if (body) matchingResponses.push(body);
57
- } catch {}
58
- }
59
- }
83
+ // Step 4: Retrieve captured data
84
+ const matchingResponses = await page.evaluate(`
85
+ () => {
86
+ const data = window.__opencli_intercepted || [];
87
+ window.__opencli_intercepted = []; // clear after reading
88
+ return data;
60
89
  }
61
- }
90
+ `);
91
+
62
92
 
63
93
  // Step 4: Select from response if specified
64
94
  let result = matchingResponses.length === 1 ? matchingResponses[0] :
@@ -57,6 +57,30 @@ describe('evalExpr', () => {
57
57
  it('resolves simple path', () => {
58
58
  expect(evalExpr('item.title', { item: { title: 'Test' } })).toBe('Test');
59
59
  });
60
+ it('applies join filter', () => {
61
+ expect(evalExpr('item.tags | join(,)', { item: { tags: ['a', 'b', 'c'] } })).toBe('a,b,c');
62
+ });
63
+ it('applies upper filter', () => {
64
+ expect(evalExpr('item.name | upper', { item: { name: 'hello' } })).toBe('HELLO');
65
+ });
66
+ it('applies lower filter', () => {
67
+ expect(evalExpr('item.name | lower', { item: { name: 'HELLO' } })).toBe('hello');
68
+ });
69
+ it('applies truncate filter', () => {
70
+ expect(evalExpr('item.text | truncate(5)', { item: { text: 'Hello World!' } })).toBe('Hello...');
71
+ });
72
+ it('chains filters', () => {
73
+ expect(evalExpr('item.name | upper | truncate(3)', { item: { name: 'hello' } })).toBe('HEL...');
74
+ });
75
+ it('applies length filter', () => {
76
+ expect(evalExpr('item.items | length', { item: { items: [1, 2, 3] } })).toBe(3);
77
+ });
78
+ it('applies json filter to strings with quotes', () => {
79
+ expect(evalExpr('args.keyword | json', { args: { keyword: "O'Reilly" } })).toBe('"O\'Reilly"');
80
+ });
81
+ it('applies json filter to nullish values', () => {
82
+ expect(evalExpr('args.keyword | json', { args: {} })).toBe('null');
83
+ });
60
84
  });
61
85
 
62
86
  describe('render', () => {
@@ -11,8 +11,17 @@ export interface RenderContext {
11
11
 
12
12
  export function render(template: any, ctx: RenderContext): any {
13
13
  if (typeof template !== 'string') return template;
14
- const fullMatch = template.match(/^\$\{\{\s*(.*?)\s*\}\}$/);
15
- if (fullMatch) return evalExpr(fullMatch[1].trim(), ctx);
14
+ // Full expression: entire string is a single ${{ ... }}
15
+ // Use [^}] to prevent matching across }} boundaries (e.g. "${{ a }}-${{ b }}")
16
+ const fullMatch = template.match(/^\$\{\{\s*([^}]*(?:\}[^}][^}]*)*)\s*\}\}$/);
17
+ if (fullMatch && !template.includes('}}-') && !template.includes('}}${{')) return evalExpr(fullMatch[1].trim(), ctx);
18
+ // Check if the entire string is a single expression (no other text around it)
19
+ const singleExpr = template.match(/^\$\{\{\s*([\s\S]*?)\s*\}\}$/);
20
+ if (singleExpr) {
21
+ // Verify it's truly a single expression (no other ${{ inside)
22
+ const inner = singleExpr[1];
23
+ if (!inner.includes('${{')) return evalExpr(inner.trim(), ctx);
24
+ }
16
25
  return template.replace(/\$\{\{\s*(.*?)\s*\}\}/g, (_m, expr) => String(evalExpr(expr.trim(), ctx)));
17
26
  }
18
27
 
@@ -22,18 +31,14 @@ export function evalExpr(expr: string, ctx: RenderContext): any {
22
31
  const data = ctx.data;
23
32
  const index = ctx.index ?? 0;
24
33
 
25
- // Default filter: args.limit | default(20)
26
- if (expr.includes('|') && expr.includes('default(')) {
27
- const [mainExpr, rest] = expr.split('|', 2);
28
- const defaultMatch = rest.match(/default\((.+?)\)/);
29
- const defaultVal = defaultMatch ? defaultMatch[1] : null;
30
- const result = resolvePath(mainExpr.trim(), { args, item, data, index });
31
- if (result === null || result === undefined) {
32
- if (defaultVal !== null) {
33
- const intVal = parseInt(defaultVal!, 10);
34
- if (!isNaN(intVal) && String(intVal) === defaultVal!.trim()) return intVal;
35
- return defaultVal!.replace(/^['"]|['"]$/g, '');
36
- }
34
+ // ── Pipe filters: expr | filter1(arg) | filter2 ──
35
+ // Supports: default(val), join(sep), upper, lower, truncate(n), trim, replace(old,new)
36
+ if (expr.includes('|') && !expr.includes('||')) {
37
+ const segments = expr.split('|').map(s => s.trim());
38
+ const mainExpr = segments[0];
39
+ let result = resolvePath(mainExpr, { args, item, data, index });
40
+ for (let i = 1; i < segments.length; i++) {
41
+ result = applyFilter(segments[i], result);
37
42
  }
38
43
  return result;
39
44
  }
@@ -66,6 +71,59 @@ export function evalExpr(expr: string, ctx: RenderContext): any {
66
71
  return resolvePath(expr, { args, item, data, index });
67
72
  }
68
73
 
74
+ /**
75
+ * Apply a named filter to a value.
76
+ * Supported filters:
77
+ * default(val), join(sep), upper, lower, truncate(n), trim,
78
+ * replace(old,new), keys, length, first, last, json
79
+ */
80
+ function applyFilter(filterExpr: string, value: any): any {
81
+ const match = filterExpr.match(/^(\w+)(?:\((.+)\))?$/);
82
+ if (!match) return value;
83
+ const [, name, rawArgs] = match;
84
+ const filterArg = rawArgs?.replace(/^['"]|['"]$/g, '') ?? '';
85
+
86
+ switch (name) {
87
+ case 'default': {
88
+ if (value === null || value === undefined || value === '') {
89
+ const intVal = parseInt(filterArg, 10);
90
+ if (!isNaN(intVal) && String(intVal) === filterArg.trim()) return intVal;
91
+ return filterArg;
92
+ }
93
+ return value;
94
+ }
95
+ case 'join':
96
+ return Array.isArray(value) ? value.join(filterArg || ', ') : value;
97
+ case 'upper':
98
+ return typeof value === 'string' ? value.toUpperCase() : value;
99
+ case 'lower':
100
+ return typeof value === 'string' ? value.toLowerCase() : value;
101
+ case 'trim':
102
+ return typeof value === 'string' ? value.trim() : value;
103
+ case 'truncate': {
104
+ const n = parseInt(filterArg, 10) || 50;
105
+ return typeof value === 'string' && value.length > n ? value.slice(0, n) + '...' : value;
106
+ }
107
+ case 'replace': {
108
+ if (typeof value !== 'string') return value;
109
+ const parts = rawArgs?.split(',').map(s => s.trim().replace(/^['"]|['"]$/g, '')) ?? [];
110
+ return parts.length >= 2 ? value.replaceAll(parts[0], parts[1]) : value;
111
+ }
112
+ case 'keys':
113
+ return value && typeof value === 'object' ? Object.keys(value) : value;
114
+ case 'length':
115
+ return Array.isArray(value) ? value.length : typeof value === 'string' ? value.length : value;
116
+ case 'first':
117
+ return Array.isArray(value) ? value[0] : value;
118
+ case 'last':
119
+ return Array.isArray(value) ? value[value.length - 1] : value;
120
+ case 'json':
121
+ return JSON.stringify(value ?? null);
122
+ default:
123
+ return value;
124
+ }
125
+ }
126
+
69
127
  export function resolvePath(pathStr: string, ctx: RenderContext): any {
70
128
  const args = ctx.args ?? {};
71
129
  const item = ctx.item ?? {};
package/src/types.ts CHANGED
@@ -20,4 +20,7 @@ export interface IPage {
20
20
  networkRequests(includeStatic?: boolean): Promise<any>;
21
21
  consoleMessages(level?: string): Promise<any>;
22
22
  scroll(direction?: string, amount?: number): Promise<void>;
23
+ autoScroll(options?: { times?: number; delayMs?: number }): Promise<void>;
24
+ installInterceptor(pattern: string): Promise<void>;
25
+ getInterceptedRequests(): Promise<any[]>;
23
26
  }
@@ -1,22 +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 './github/search.js';
13
- import './zhihu/question.js';
14
- import './xiaohongshu/search.js';
15
- import './bbc/news.js';
16
- import './weibo/hot.js';
17
- import './boss/search.js';
18
- import './yahoo-finance/quote.js';
19
- import './reuters/search.js';
20
- import './smzdm/search.js';
21
- import './ctrip/search.js';
22
- import './youtube/search.js';
@@ -1,34 +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
- // github
14
- import './github/search.js';
15
- // zhihu
16
- import './zhihu/question.js';
17
- // xiaohongshu
18
- import './xiaohongshu/search.js';
19
- // bbc
20
- import './bbc/news.js';
21
- // weibo
22
- import './weibo/hot.js';
23
- // boss
24
- import './boss/search.js';
25
- // yahoo-finance
26
- import './yahoo-finance/quote.js';
27
- // reuters
28
- import './reuters/search.js';
29
- // smzdm
30
- import './smzdm/search.js';
31
- // ctrip
32
- import './ctrip/search.js';
33
- // youtube
34
- import './youtube/search.js';
package/src/clis/index.ts DELETED
@@ -1,46 +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
-
7
- // bilibili
8
- import './bilibili/search.js';
9
- import './bilibili/me.js';
10
- import './bilibili/favorite.js';
11
- import './bilibili/history.js';
12
- import './bilibili/feed.js';
13
- import './bilibili/user-videos.js';
14
-
15
- // github
16
- import './github/search.js';
17
-
18
- // zhihu
19
- import './zhihu/question.js';
20
-
21
- // xiaohongshu
22
- import './xiaohongshu/search.js';
23
-
24
- // bbc
25
- import './bbc/news.js';
26
-
27
- // weibo
28
- import './weibo/hot.js';
29
-
30
- // boss
31
- import './boss/search.js';
32
-
33
- // yahoo-finance
34
- import './yahoo-finance/quote.js';
35
-
36
- // reuters
37
- import './reuters/search.js';
38
-
39
- // smzdm
40
- import './smzdm/search.js';
41
-
42
- // ctrip
43
- import './ctrip/search.js';
44
-
45
- // youtube
46
- import './youtube/search.js';