@jackwener/opencli 0.9.5 → 0.9.8
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/ISSUE_TEMPLATE/bug_report.yml +83 -0
- package/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +42 -0
- package/.github/ISSUE_TEMPLATE/new_site_adapter.yml +57 -0
- package/.github/dependabot.yml +27 -0
- package/.github/pull_request_template.md +24 -0
- package/.github/workflows/ci.yml +14 -8
- package/.github/workflows/e2e-headed.yml +6 -2
- package/.github/workflows/pkg-pr-new.yml +2 -2
- package/.github/workflows/release-please.yml +25 -0
- package/.github/workflows/release.yml +2 -2
- package/.github/workflows/security.yml +36 -0
- package/CLI-ELECTRON.md +89 -36
- package/CONTRIBUTING.md +167 -0
- package/README.md +98 -32
- package/README.zh-CN.md +99 -33
- package/dist/browser/discover.js +22 -7
- package/dist/browser.test.js +23 -0
- package/dist/build-manifest.d.ts +26 -0
- package/dist/build-manifest.js +132 -60
- package/dist/build-manifest.test.d.ts +1 -0
- package/dist/build-manifest.test.js +26 -0
- package/dist/cli-manifest.json +1875 -271
- package/dist/clis/antigravity/model.js +2 -2
- package/dist/clis/antigravity/send.js +2 -2
- package/dist/clis/bilibili/download.d.ts +10 -0
- package/dist/clis/bilibili/download.js +135 -0
- package/dist/clis/chatgpt/ask.d.ts +1 -0
- package/dist/clis/chatgpt/ask.js +68 -0
- package/dist/clis/chatgpt/send.js +11 -0
- package/dist/clis/chatwise/ask.d.ts +1 -0
- package/dist/clis/chatwise/ask.js +76 -0
- package/dist/clis/chatwise/export.d.ts +1 -0
- package/dist/clis/chatwise/export.js +46 -0
- package/dist/clis/chatwise/history.d.ts +1 -0
- package/dist/clis/chatwise/history.js +43 -0
- package/dist/clis/chatwise/model.d.ts +1 -0
- package/dist/clis/chatwise/model.js +81 -0
- package/dist/clis/chatwise/new.d.ts +1 -0
- package/dist/clis/chatwise/new.js +18 -0
- package/dist/clis/chatwise/read.d.ts +1 -0
- package/dist/clis/chatwise/read.js +39 -0
- package/dist/clis/chatwise/screenshot.d.ts +1 -0
- package/dist/clis/chatwise/screenshot.js +27 -0
- package/dist/clis/chatwise/send.d.ts +1 -0
- package/dist/clis/chatwise/send.js +45 -0
- package/dist/clis/chatwise/status.d.ts +1 -0
- package/dist/clis/chatwise/status.js +22 -0
- package/dist/clis/codex/ask.d.ts +1 -0
- package/dist/clis/codex/ask.js +67 -0
- package/dist/clis/codex/export.d.ts +1 -0
- package/dist/clis/codex/export.js +37 -0
- package/dist/clis/codex/history.d.ts +1 -0
- package/dist/clis/codex/history.js +43 -0
- package/dist/clis/codex/read.js +3 -5
- package/dist/clis/codex/screenshot.d.ts +1 -0
- package/dist/clis/codex/screenshot.js +27 -0
- package/dist/clis/codex/send.js +3 -6
- package/dist/clis/codex/status.js +2 -1
- package/dist/clis/cursor/ask.d.ts +1 -0
- package/dist/clis/cursor/ask.js +69 -0
- package/dist/clis/cursor/composer.js +9 -28
- package/dist/clis/cursor/export.d.ts +1 -0
- package/dist/clis/cursor/export.js +51 -0
- package/dist/clis/cursor/history.d.ts +1 -0
- package/dist/clis/cursor/history.js +43 -0
- package/dist/clis/cursor/new.js +4 -13
- package/dist/clis/cursor/screenshot.d.ts +1 -0
- package/dist/clis/cursor/screenshot.js +31 -0
- package/dist/clis/discord-app/channels.d.ts +1 -0
- package/dist/clis/discord-app/channels.js +45 -0
- package/dist/clis/discord-app/members.d.ts +1 -0
- package/dist/clis/discord-app/members.js +38 -0
- package/dist/clis/discord-app/read.d.ts +1 -0
- package/dist/clis/discord-app/read.js +45 -0
- package/dist/clis/discord-app/search.d.ts +1 -0
- package/dist/clis/discord-app/search.js +56 -0
- package/dist/clis/discord-app/send.d.ts +1 -0
- package/dist/clis/discord-app/send.js +27 -0
- package/dist/clis/discord-app/servers.d.ts +1 -0
- package/dist/clis/discord-app/servers.js +36 -0
- package/dist/clis/discord-app/status.d.ts +1 -0
- package/dist/clis/discord-app/status.js +16 -0
- package/dist/clis/feishu/new.d.ts +1 -0
- package/dist/clis/feishu/new.js +27 -0
- package/dist/clis/feishu/read.d.ts +1 -0
- package/dist/clis/feishu/read.js +40 -0
- package/dist/clis/feishu/search.d.ts +1 -0
- package/dist/clis/feishu/search.js +30 -0
- package/dist/clis/feishu/send.d.ts +1 -0
- package/dist/clis/feishu/send.js +39 -0
- package/dist/clis/feishu/status.d.ts +1 -0
- package/dist/clis/feishu/status.js +28 -0
- package/dist/clis/grok/ask.d.ts +1 -0
- package/dist/clis/grok/ask.js +82 -0
- package/dist/clis/grok/debug.d.ts +1 -0
- package/dist/clis/grok/debug.js +45 -0
- package/dist/clis/jimeng/generate.yaml +84 -0
- package/dist/clis/jimeng/history.yaml +47 -0
- package/dist/clis/linux-do/categories.yaml +41 -0
- package/dist/clis/linux-do/category.yaml +49 -0
- package/dist/clis/linux-do/hot.yaml +50 -0
- package/dist/clis/linux-do/latest.yaml +40 -0
- package/dist/clis/linux-do/search.yaml +45 -0
- package/dist/clis/linux-do/topic.yaml +38 -0
- package/dist/clis/notion/export.d.ts +1 -0
- package/dist/clis/notion/export.js +31 -0
- package/dist/clis/notion/favorites.d.ts +1 -0
- package/dist/clis/notion/favorites.js +84 -0
- package/dist/clis/notion/new.d.ts +1 -0
- package/dist/clis/notion/new.js +34 -0
- package/dist/clis/notion/read.d.ts +1 -0
- package/dist/clis/notion/read.js +30 -0
- package/dist/clis/notion/search.d.ts +1 -0
- package/dist/clis/notion/search.js +46 -0
- package/dist/clis/notion/sidebar.d.ts +1 -0
- package/dist/clis/notion/sidebar.js +41 -0
- package/dist/clis/notion/status.d.ts +1 -0
- package/dist/clis/notion/status.js +16 -0
- package/dist/clis/notion/write.d.ts +1 -0
- package/dist/clis/notion/write.js +40 -0
- package/dist/clis/twitter/download.d.ts +8 -0
- package/dist/clis/twitter/download.js +204 -0
- package/dist/clis/wechat/chats.d.ts +1 -0
- package/dist/clis/wechat/chats.js +28 -0
- package/dist/clis/wechat/contacts.d.ts +1 -0
- package/dist/clis/wechat/contacts.js +28 -0
- package/dist/clis/wechat/read.d.ts +1 -0
- package/dist/clis/wechat/read.js +58 -0
- package/dist/clis/wechat/search.d.ts +1 -0
- package/dist/clis/wechat/search.js +31 -0
- package/dist/clis/wechat/send.d.ts +1 -0
- package/dist/clis/wechat/send.js +42 -0
- package/dist/clis/wechat/status.d.ts +1 -0
- package/dist/clis/wechat/status.js +29 -0
- package/dist/clis/xiaohongshu/creator-note-detail.d.ts +10 -0
- package/dist/clis/xiaohongshu/creator-note-detail.js +88 -0
- package/dist/clis/xiaohongshu/creator-notes.d.ts +11 -0
- package/dist/clis/xiaohongshu/creator-notes.js +109 -0
- package/dist/clis/xiaohongshu/creator-profile.d.ts +10 -0
- package/dist/clis/xiaohongshu/creator-profile.js +54 -0
- package/dist/clis/xiaohongshu/creator-stats.d.ts +10 -0
- package/dist/clis/xiaohongshu/creator-stats.js +74 -0
- package/dist/clis/xiaohongshu/download.d.ts +7 -0
- package/dist/clis/xiaohongshu/download.js +155 -0
- package/dist/clis/xiaohongshu/search.js +1 -1
- package/dist/clis/xiaohongshu/user-helpers.d.ts +15 -0
- package/dist/clis/xiaohongshu/user-helpers.js +67 -0
- package/dist/clis/xiaohongshu/user-helpers.test.d.ts +1 -0
- package/dist/clis/xiaohongshu/user-helpers.test.js +81 -0
- package/dist/clis/xiaohongshu/user.js +46 -29
- package/dist/clis/zhihu/download.d.ts +11 -0
- package/dist/clis/zhihu/download.js +186 -0
- package/dist/clis/zhihu/download.test.d.ts +1 -0
- package/dist/clis/zhihu/download.test.js +10 -0
- package/dist/download/index.d.ts +79 -0
- package/dist/download/index.js +325 -0
- package/dist/download/progress.d.ts +36 -0
- package/dist/download/progress.js +111 -0
- package/dist/engine.test.js +15 -0
- package/dist/main.js +16 -3
- package/dist/pipeline/registry.js +2 -0
- package/dist/pipeline/steps/download.d.ts +34 -0
- package/dist/pipeline/steps/download.js +251 -0
- package/dist/pipeline/template.js +28 -0
- package/package.json +4 -3
- package/scripts/test-site.mjs +70 -0
- package/src/browser/discover.ts +23 -7
- package/src/browser.test.ts +23 -0
- package/src/build-manifest.test.ts +28 -0
- package/src/build-manifest.ts +147 -57
- package/src/clis/antigravity/README.md +2 -3
- package/src/clis/antigravity/README.zh-CN.md +2 -3
- package/src/clis/antigravity/SKILL.md +1 -1
- package/src/clis/antigravity/model.ts +2 -2
- package/src/clis/antigravity/send.ts +2 -2
- package/src/clis/bilibili/download.ts +161 -0
- package/src/clis/chatgpt/README.md +25 -16
- package/src/clis/chatgpt/README.zh-CN.md +27 -18
- package/src/clis/chatgpt/ask.ts +77 -0
- package/src/clis/chatgpt/send.ts +12 -0
- package/src/clis/chatwise/README.md +38 -0
- package/src/clis/chatwise/README.zh-CN.md +38 -0
- package/src/clis/chatwise/ask.ts +87 -0
- package/src/clis/chatwise/export.ts +51 -0
- package/src/clis/chatwise/history.ts +47 -0
- package/src/clis/chatwise/model.ts +87 -0
- package/src/clis/chatwise/new.ts +21 -0
- package/src/clis/chatwise/read.ts +42 -0
- package/src/clis/chatwise/screenshot.ts +33 -0
- package/src/clis/chatwise/send.ts +50 -0
- package/src/clis/chatwise/status.ts +25 -0
- package/src/clis/codex/ask.ts +77 -0
- package/src/clis/codex/export.ts +42 -0
- package/src/clis/codex/extract-diff.ts +1 -0
- package/src/clis/codex/history.ts +47 -0
- package/src/clis/codex/read.ts +5 -6
- package/src/clis/codex/screenshot.ts +33 -0
- package/src/clis/codex/send.ts +6 -7
- package/src/clis/codex/status.ts +4 -2
- package/src/clis/cursor/ask.ts +81 -0
- package/src/clis/cursor/composer.ts +9 -30
- package/src/clis/cursor/export.ts +57 -0
- package/src/clis/cursor/history.ts +47 -0
- package/src/clis/cursor/new.ts +4 -15
- package/src/clis/cursor/screenshot.ts +38 -0
- package/src/clis/discord-app/README.md +28 -0
- package/src/clis/discord-app/README.zh-CN.md +28 -0
- package/src/clis/discord-app/channels.ts +48 -0
- package/src/clis/discord-app/members.ts +41 -0
- package/src/clis/discord-app/read.ts +49 -0
- package/src/clis/discord-app/search.ts +64 -0
- package/src/clis/discord-app/send.ts +32 -0
- package/src/clis/discord-app/servers.ts +39 -0
- package/src/clis/discord-app/status.ts +18 -0
- package/src/clis/feishu/README.md +20 -0
- package/src/clis/feishu/README.zh-CN.md +20 -0
- package/src/clis/feishu/new.ts +32 -0
- package/src/clis/feishu/read.ts +48 -0
- package/src/clis/feishu/search.ts +35 -0
- package/src/clis/feishu/send.ts +46 -0
- package/src/clis/feishu/status.ts +34 -0
- package/src/clis/grok/ask.ts +90 -0
- package/src/clis/grok/debug.ts +49 -0
- package/src/clis/jimeng/generate.yaml +84 -0
- package/src/clis/jimeng/history.yaml +47 -0
- package/src/clis/linux-do/categories.yaml +41 -0
- package/src/clis/linux-do/category.yaml +49 -0
- package/src/clis/linux-do/hot.yaml +50 -0
- package/src/clis/linux-do/latest.yaml +40 -0
- package/src/clis/linux-do/search.yaml +45 -0
- package/src/clis/linux-do/topic.yaml +38 -0
- package/src/clis/notion/README.md +29 -0
- package/src/clis/notion/README.zh-CN.md +29 -0
- package/src/clis/notion/export.ts +36 -0
- package/src/clis/notion/favorites.ts +87 -0
- package/src/clis/notion/new.ts +39 -0
- package/src/clis/notion/read.ts +33 -0
- package/src/clis/notion/search.ts +54 -0
- package/src/clis/notion/sidebar.ts +44 -0
- package/src/clis/notion/status.ts +18 -0
- package/src/clis/notion/write.ts +45 -0
- package/src/clis/twitter/download.ts +227 -0
- package/src/clis/wechat/README.md +28 -0
- package/src/clis/wechat/README.zh-CN.md +28 -0
- package/src/clis/wechat/chats.ts +33 -0
- package/src/clis/wechat/contacts.ts +33 -0
- package/src/clis/wechat/read.ts +72 -0
- package/src/clis/wechat/search.ts +36 -0
- package/src/clis/wechat/send.ts +49 -0
- package/src/clis/wechat/status.ts +35 -0
- package/src/clis/xiaohongshu/creator-note-detail.ts +95 -0
- package/src/clis/xiaohongshu/creator-notes.ts +116 -0
- package/src/clis/xiaohongshu/creator-profile.ts +60 -0
- package/src/clis/xiaohongshu/creator-stats.ts +81 -0
- package/src/clis/xiaohongshu/download.ts +173 -0
- package/src/clis/xiaohongshu/search.ts +1 -1
- package/src/clis/xiaohongshu/user-helpers.test.ts +106 -0
- package/src/clis/xiaohongshu/user-helpers.ts +85 -0
- package/src/clis/xiaohongshu/user.ts +52 -32
- package/src/clis/zhihu/download.test.ts +12 -0
- package/src/clis/zhihu/download.ts +223 -0
- package/src/download/index.ts +395 -0
- package/src/download/progress.ts +125 -0
- package/src/engine.test.ts +17 -0
- package/src/main.ts +12 -3
- package/src/pipeline/registry.ts +2 -0
- package/src/pipeline/steps/download.ts +310 -0
- package/src/pipeline/template.ts +26 -0
- package/tests/e2e/browser-auth.test.ts +25 -0
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Contributing to OpenCLI
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in contributing to OpenCLI.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# 1. Fork & clone
|
|
9
|
+
git clone git@github.com:<your-username>/opencli.git
|
|
10
|
+
cd opencli
|
|
11
|
+
|
|
12
|
+
# 2. Install dependencies
|
|
13
|
+
npm install
|
|
14
|
+
|
|
15
|
+
# 3. Build
|
|
16
|
+
npm run build
|
|
17
|
+
|
|
18
|
+
# 4. Run a few checks
|
|
19
|
+
npx tsc --noEmit
|
|
20
|
+
npx vitest run src/
|
|
21
|
+
|
|
22
|
+
# 5. Link globally (optional, for testing `opencli` command)
|
|
23
|
+
npm link
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Adding a New Site Adapter
|
|
27
|
+
|
|
28
|
+
This is the most common type of contribution. Start with YAML when possible, and use TypeScript only when you need browser-side logic or multi-step flows.
|
|
29
|
+
|
|
30
|
+
### YAML Adapter (Recommended for data-fetching commands)
|
|
31
|
+
|
|
32
|
+
Create a file like `src/clis/<site>/<command>.yaml`:
|
|
33
|
+
|
|
34
|
+
```yaml
|
|
35
|
+
site: mysite
|
|
36
|
+
name: trending
|
|
37
|
+
description: Trending posts on MySite
|
|
38
|
+
domain: www.mysite.com
|
|
39
|
+
strategy: public # public | cookie | header
|
|
40
|
+
browser: false # true if browser session is needed
|
|
41
|
+
|
|
42
|
+
args:
|
|
43
|
+
limit:
|
|
44
|
+
type: int
|
|
45
|
+
default: 20
|
|
46
|
+
description: Number of items
|
|
47
|
+
|
|
48
|
+
pipeline:
|
|
49
|
+
- fetch:
|
|
50
|
+
url: https://api.mysite.com/trending
|
|
51
|
+
|
|
52
|
+
- map:
|
|
53
|
+
rank: ${{ index + 1 }}
|
|
54
|
+
title: ${{ item.title }}
|
|
55
|
+
score: ${{ item.score }}
|
|
56
|
+
url: ${{ item.url }}
|
|
57
|
+
|
|
58
|
+
- limit: ${{ args.limit }}
|
|
59
|
+
|
|
60
|
+
columns: [rank, title, score, url]
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
See [`hackernews/top.yaml`](src/clis/hackernews/top.yaml) for a real example.
|
|
64
|
+
|
|
65
|
+
### TypeScript Adapter (For complex browser interactions)
|
|
66
|
+
|
|
67
|
+
Create a file like `src/clis/<site>/<command>.ts`:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import { cli, Strategy } from '../../registry.js';
|
|
71
|
+
|
|
72
|
+
cli({
|
|
73
|
+
site: 'mysite',
|
|
74
|
+
name: 'search',
|
|
75
|
+
description: 'Search MySite',
|
|
76
|
+
domain: 'www.mysite.com',
|
|
77
|
+
strategy: Strategy.COOKIE,
|
|
78
|
+
args: [
|
|
79
|
+
{ name: 'query', required: true, help: 'Search query' },
|
|
80
|
+
{ name: 'limit', type: 'int', default: 10, help: 'Max results' },
|
|
81
|
+
],
|
|
82
|
+
columns: ['title', 'url', 'date'],
|
|
83
|
+
|
|
84
|
+
func: async (page, kwargs) => {
|
|
85
|
+
const { query, limit = 10 } = kwargs;
|
|
86
|
+
await page.goto('https://www.mysite.com');
|
|
87
|
+
|
|
88
|
+
const data = await page.evaluate(`
|
|
89
|
+
(async () => {
|
|
90
|
+
const res = await fetch('/api/search?q=${encodeURIComponent(query)}', {
|
|
91
|
+
credentials: 'include'
|
|
92
|
+
});
|
|
93
|
+
return (await res.json()).results;
|
|
94
|
+
})()
|
|
95
|
+
`);
|
|
96
|
+
|
|
97
|
+
return data.slice(0, Number(limit)).map((item: any) => ({
|
|
98
|
+
title: item.title,
|
|
99
|
+
url: item.url,
|
|
100
|
+
date: item.created_at,
|
|
101
|
+
}));
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Use `opencli explore <url>` to discover APIs and see [CLI-EXPLORER.md](./CLI-EXPLORER.md) if you need the full adapter workflow.
|
|
107
|
+
|
|
108
|
+
### Validate Your Adapter
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# Validate YAML syntax and schema
|
|
112
|
+
opencli validate
|
|
113
|
+
|
|
114
|
+
# Test your command
|
|
115
|
+
opencli <site> <command> --limit 3 -f json
|
|
116
|
+
|
|
117
|
+
# Verbose mode for debugging
|
|
118
|
+
opencli <site> <command> -v
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Testing
|
|
122
|
+
|
|
123
|
+
See [TESTING.md](./TESTING.md) for the full guide and exact test locations.
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npx vitest run src/ # Unit tests
|
|
127
|
+
npx vitest run tests/e2e/ # E2E tests
|
|
128
|
+
npx vitest run # All tests
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Code Style
|
|
132
|
+
|
|
133
|
+
- **TypeScript strict mode** — avoid `any` where possible.
|
|
134
|
+
- **ES Modules** — use `.js` extensions in imports (TypeScript output).
|
|
135
|
+
- **Naming**: `kebab-case` for files, `camelCase` for variables/functions, `PascalCase` for types/classes.
|
|
136
|
+
- **No default exports** — use named exports.
|
|
137
|
+
|
|
138
|
+
## Commit Convention
|
|
139
|
+
|
|
140
|
+
We use [Conventional Commits](https://www.conventionalcommits.org/):
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
feat(twitter): add thread command
|
|
144
|
+
fix(browser): handle CDP timeout gracefully
|
|
145
|
+
docs: update CONTRIBUTING.md
|
|
146
|
+
test(reddit): add e2e test for save command
|
|
147
|
+
chore: bump vitest to v4
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Common scopes: site name (`twitter`, `reddit`) or module name (`browser`, `pipeline`, `engine`).
|
|
151
|
+
|
|
152
|
+
## Submitting a Pull Request
|
|
153
|
+
|
|
154
|
+
1. Create a feature branch: `git checkout -b feat/mysite-trending`
|
|
155
|
+
2. Make your changes and add tests when relevant
|
|
156
|
+
3. Run the checks that apply:
|
|
157
|
+
```bash
|
|
158
|
+
npx tsc --noEmit # Type check
|
|
159
|
+
npx vitest run src/ # Unit tests
|
|
160
|
+
opencli validate # YAML validation (if applicable)
|
|
161
|
+
```
|
|
162
|
+
4. Commit using conventional commit format
|
|
163
|
+
5. Push and open a PR
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
By contributing, you agree that your contributions will be licensed under the [Apache-2.0 License](./LICENSE).
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# OpenCLI
|
|
2
2
|
|
|
3
3
|
> **Make any website or Electron App your CLI.**
|
|
4
|
-
> Zero risk · Reuse Chrome login · AI-powered discovery ·
|
|
4
|
+
> Zero risk · Reuse Chrome login · AI-powered discovery · Browser + Desktop automation
|
|
5
5
|
|
|
6
6
|
[中文文档](./README.zh-CN.md)
|
|
7
7
|
|
|
@@ -22,6 +22,7 @@ Turn ANY Electron application into a CLI tool! Recombine, script, and extend app
|
|
|
22
22
|
- [Prerequisites](#prerequisites)
|
|
23
23
|
- [Quick Start](#quick-start)
|
|
24
24
|
- [Built-in Commands](#built-in-commands)
|
|
25
|
+
- [Download Support](#download-support)
|
|
25
26
|
- [Output Formats](#output-formats)
|
|
26
27
|
- [For AI Agents (Developer Guide)](#for-ai-agents-developer-guide)
|
|
27
28
|
- [Remote Chrome (Server/Headless)](#remote-chrome-serverheadless)
|
|
@@ -43,7 +44,7 @@ Turn ANY Electron application into a CLI tool! Recombine, script, and extend app
|
|
|
43
44
|
|
|
44
45
|
## Prerequisites
|
|
45
46
|
|
|
46
|
-
- **Node.js**: >=
|
|
47
|
+
- **Node.js**: >= 20.0.0
|
|
47
48
|
- **Chrome** running **and logged into the target site** (e.g. bilibili.com, zhihu.com, xiaohongshu.com).
|
|
48
49
|
|
|
49
50
|
> **⚠️ Important**: Browser commands reuse your Chrome login session. You must be logged into the target website in Chrome before running commands. If you get empty data or errors, check your login status first.
|
|
@@ -143,34 +144,99 @@ npm install -g @jackwener/opencli@latest
|
|
|
143
144
|
|
|
144
145
|
## Built-in Commands
|
|
145
146
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
| Site | Commands |
|
|
149
|
-
|
|
150
|
-
| **twitter** | `trending` `bookmarks` `profile` `search` `timeline` `thread` `following` `followers` `notifications` `post` `reply` `delete` `like` `article` `follow` `unfollow` `bookmark` `unbookmark`
|
|
151
|
-
| **reddit** | `hot` `frontpage` `popular` `search` `subreddit` `read` `user` `user-posts` `user-comments` `upvote` `save` `comment` `subscribe` `saved` `upvoted` |
|
|
152
|
-
| **
|
|
153
|
-
| **
|
|
154
|
-
| **codex** | `status` `send` `read` `new` `extract-diff` `model`
|
|
155
|
-
| **
|
|
156
|
-
| **
|
|
157
|
-
| **
|
|
158
|
-
| **
|
|
159
|
-
| **
|
|
160
|
-
| **
|
|
161
|
-
| **
|
|
162
|
-
| **
|
|
163
|
-
| **
|
|
164
|
-
| **
|
|
165
|
-
| **
|
|
166
|
-
| **
|
|
167
|
-
| **
|
|
168
|
-
| **
|
|
169
|
-
| **
|
|
170
|
-
| **
|
|
171
|
-
| **
|
|
172
|
-
| **
|
|
173
|
-
| **
|
|
147
|
+
Run `opencli list` for the live registry.
|
|
148
|
+
|
|
149
|
+
| Site | Commands | Mode |
|
|
150
|
+
|------|----------|------|
|
|
151
|
+
| **twitter** | `trending` `bookmarks` `profile` `search` `timeline` `thread` `following` `followers` `notifications` `post` `reply` `delete` `like` `article` `follow` `unfollow` `bookmark` `unbookmark` `download` | 🔐 Browser |
|
|
152
|
+
| **reddit** | `hot` `frontpage` `popular` `search` `subreddit` `read` `user` `user-posts` `user-comments` `upvote` `save` `comment` `subscribe` `saved` `upvoted` | 🔐 Browser |
|
|
153
|
+
| **cursor** | `status` `send` `read` `new` `dump` `composer` `model` `extract-code` `ask` `screenshot` `history` `export` | 🖥️ Desktop |
|
|
154
|
+
| **bilibili** | `hot` `search` `me` `favorite` `history` `feed` `subtitle` `dynamic` `ranking` `following` `user-videos` `download` | 🔐 Browser |
|
|
155
|
+
| **codex** | `status` `send` `read` `new` `extract-diff` `model` `ask` `screenshot` `history` `export` | 🖥️ Desktop |
|
|
156
|
+
| **chatwise** | `status` `new` `send` `read` `ask` `model` `history` `export` `screenshot` | 🖥️ Desktop |
|
|
157
|
+
| **notion** | `status` `search` `read` `new` `write` `sidebar` `favorites` `export` | 🖥️ Desktop |
|
|
158
|
+
| **discord-app** | `status` `send` `read` `channels` `servers` `search` `members` | 🖥️ Desktop |
|
|
159
|
+
| **v2ex** | `hot` `latest` `topic` `daily` `me` `notifications` | 🌐 / 🔐 |
|
|
160
|
+
| **xueqiu** | `feed` `hot-stock` `hot` `search` `stock` `watchlist` | 🔐 Browser |
|
|
161
|
+
| **antigravity** | `status` `send` `read` `new` `evaluate` | 🖥️ Desktop |
|
|
162
|
+
| **chatgpt** | `status` `new` `send` `read` `ask` | 🖥️ Desktop |
|
|
163
|
+
| **xiaohongshu** | `search` `notifications` `feed` `me` `user` `download` | 🔐 Browser |
|
|
164
|
+
| **xiaoyuzhou** | `podcast` `podcast-episodes` `episode` | 🌐 Public |
|
|
165
|
+
| **zhihu** | `hot` `search` `question` `download` | 🔐 Browser |
|
|
166
|
+
| **youtube** | `search` `video` `transcript` | 🔐 Browser |
|
|
167
|
+
| **boss** | `search` `detail` | 🔐 Browser |
|
|
168
|
+
| **coupang** | `search` `add-to-cart` | 🔐 Browser |
|
|
169
|
+
| **bbc** | `news` | 🌐 Public |
|
|
170
|
+
| **ctrip** | `search` | 🔐 Browser |
|
|
171
|
+
| **github** | `search` | 🌐 Public |
|
|
172
|
+
| **hackernews** | `top` | 🌐 Public |
|
|
173
|
+
| **linkedin** | `search` | 🔐 Browser |
|
|
174
|
+
| **reuters** | `search` | 🔐 Browser |
|
|
175
|
+
| **smzdm** | `search` | 🔐 Browser |
|
|
176
|
+
| **weibo** | `hot` | 🔐 Browser |
|
|
177
|
+
| **yahoo-finance** | `quote` | 🔐 Browser |
|
|
178
|
+
|
|
179
|
+
## Download Support
|
|
180
|
+
|
|
181
|
+
OpenCLI supports downloading images, videos, and articles from supported platforms.
|
|
182
|
+
|
|
183
|
+
### Supported Platforms
|
|
184
|
+
|
|
185
|
+
| Platform | Content Types | Notes |
|
|
186
|
+
|----------|---------------|-------|
|
|
187
|
+
| **xiaohongshu** | Images, Videos | Downloads all media from a note |
|
|
188
|
+
| **bilibili** | Videos | Requires `yt-dlp` installed |
|
|
189
|
+
| **twitter** | Images, Videos | Downloads from user media tab or single tweet |
|
|
190
|
+
| **zhihu** | Articles (Markdown) | Exports articles with optional image download |
|
|
191
|
+
|
|
192
|
+
### Prerequisites
|
|
193
|
+
|
|
194
|
+
For video downloads from streaming platforms, you need to install `yt-dlp`:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
# Install yt-dlp
|
|
198
|
+
pip install yt-dlp
|
|
199
|
+
# or
|
|
200
|
+
brew install yt-dlp
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Usage Examples
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
# Download images/videos from Xiaohongshu note
|
|
207
|
+
opencli xiaohongshu download --note-id abc123 --output ./xhs
|
|
208
|
+
|
|
209
|
+
# Download Bilibili video (requires yt-dlp)
|
|
210
|
+
opencli bilibili download --bvid BV1xxx --output ./bilibili
|
|
211
|
+
opencli bilibili download --bvid BV1xxx --quality 1080p # Specify quality
|
|
212
|
+
|
|
213
|
+
# Download Twitter media from user
|
|
214
|
+
opencli twitter download --username elonmusk --limit 20 --output ./twitter
|
|
215
|
+
|
|
216
|
+
# Download single tweet media
|
|
217
|
+
opencli twitter download --tweet-url "https://x.com/user/status/123" --output ./twitter
|
|
218
|
+
|
|
219
|
+
# Export Zhihu article to Markdown
|
|
220
|
+
opencli zhihu download --url "https://zhuanlan.zhihu.com/p/xxx" --output ./zhihu
|
|
221
|
+
|
|
222
|
+
# Export with local images
|
|
223
|
+
opencli zhihu download --url "https://zhuanlan.zhihu.com/p/xxx" --download-images
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Pipeline Step (for YAML adapters)
|
|
227
|
+
|
|
228
|
+
The `download` step can be used in YAML pipelines:
|
|
229
|
+
|
|
230
|
+
```yaml
|
|
231
|
+
pipeline:
|
|
232
|
+
- fetch: https://api.example.com/media
|
|
233
|
+
- download:
|
|
234
|
+
url: ${{ item.imageUrl }}
|
|
235
|
+
dir: ./downloads
|
|
236
|
+
filename: ${{ item.title | sanitize }}.jpg
|
|
237
|
+
concurrency: 5
|
|
238
|
+
skip_existing: true
|
|
239
|
+
```
|
|
174
240
|
|
|
175
241
|
## Output Formats
|
|
176
242
|
|
|
@@ -215,7 +281,7 @@ Explore outputs to `.opencli/explore/<site>/` (manifest.json, endpoints.json, ca
|
|
|
215
281
|
|
|
216
282
|
See **[TESTING.md](./TESTING.md)** for the full testing guide, including:
|
|
217
283
|
|
|
218
|
-
- Current test coverage (unit + E2E tests across
|
|
284
|
+
- Current test coverage (unit + E2E tests across browser and desktop adapters)
|
|
219
285
|
- How to run tests locally
|
|
220
286
|
- How to add tests when creating new adapters
|
|
221
287
|
- CI/CD pipeline with sharding
|
|
@@ -237,7 +303,7 @@ npx vitest run tests/e2e/ # E2E tests
|
|
|
237
303
|
- **Empty data returns or 'Unauthorized' error**
|
|
238
304
|
- Your login session in Chrome might have expired. Open a normal Chrome tab, navigate to the target site, and log in or refresh the page to prove you are human.
|
|
239
305
|
- **Node API errors**
|
|
240
|
-
- Make sure you are using Node.js >=
|
|
306
|
+
- Make sure you are using Node.js >= 20. Some dependencies require modern Node APIs.
|
|
241
307
|
- **Token issues**
|
|
242
308
|
- Run `opencli doctor` to diagnose token configuration across all tools.
|
|
243
309
|
|
package/README.zh-CN.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# OpenCLI
|
|
2
2
|
|
|
3
3
|
> **把任何网站或 Electron 应用变成你的命令行工具。**
|
|
4
|
-
> 零风控 · 复用 Chrome 登录 · AI 自动发现接口 ·
|
|
4
|
+
> 零风控 · 复用 Chrome 登录 · AI 自动发现接口 · 浏览器与桌面端自动化
|
|
5
5
|
|
|
6
6
|
[English](./README.md)
|
|
7
7
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
[](https://nodejs.org)
|
|
10
10
|
[](./LICENSE)
|
|
11
11
|
|
|
12
|
-
OpenCLI 将任何网站或 Electron 应用(如 Antigravity)变成命令行工具 — B站、知乎、小红书、Twitter/X、Reddit、YouTube 等
|
|
12
|
+
OpenCLI 将任何网站或 Electron 应用(如 Antigravity)变成命令行工具 — B站、知乎、小红书、Twitter/X、Reddit、YouTube 等[多种站点与应用](#内置命令) — 复用浏览器登录态,AI 驱动探索。
|
|
13
13
|
|
|
14
14
|
🔥 **opencli 支持 CLI 化所有 electron 应用!最强大更新来袭!** 🔥
|
|
15
15
|
CLI all electron!现在支持把所有 electron 应用 CLI 化,从而组合出各种神奇的能力。
|
|
@@ -24,6 +24,7 @@ CLI all electron!现在支持把所有 electron 应用 CLI 化,从而组合
|
|
|
24
24
|
- [前置要求](#前置要求)
|
|
25
25
|
- [快速开始](#快速开始)
|
|
26
26
|
- [内置命令](#内置命令)
|
|
27
|
+
- [下载支持](#下载支持)
|
|
27
28
|
- [输出格式](#输出格式)
|
|
28
29
|
- [致 AI Agent(开发者指南)](#致-ai-agent开发者指南)
|
|
29
30
|
- [远程 Chrome(服务器/无头环境)](#远程-chrome服务器无头环境)
|
|
@@ -36,7 +37,7 @@ CLI all electron!现在支持把所有 electron 应用 CLI 化,从而组合
|
|
|
36
37
|
## 亮点
|
|
37
38
|
|
|
38
39
|
- **CLI All Electron** — 支持把所有 electron 应用(如 Antigravity Ultra)CLI 化,让 AI 控制自己!
|
|
39
|
-
- **多站点覆盖** — B站、知乎、小红书、Twitter、Reddit
|
|
40
|
+
- **多站点覆盖** — 覆盖 B站、知乎、小红书、Twitter、Reddit,以及多种桌面应用
|
|
40
41
|
- **零风控** — 复用 Chrome 登录态,无需存储任何凭证
|
|
41
42
|
- **自修复配置** — `opencli setup` 自动发现 Token;`opencli doctor` 诊断 10+ 工具配置;`--fix` 一键修复
|
|
42
43
|
- **AI 原生** — `explore` 自动发现 API,`synthesize` 生成适配器,`cascade` 探测认证策略
|
|
@@ -44,7 +45,7 @@ CLI all electron!现在支持把所有 electron 应用 CLI 化,从而组合
|
|
|
44
45
|
|
|
45
46
|
## 前置要求
|
|
46
47
|
|
|
47
|
-
- **Node.js**: >=
|
|
48
|
+
- **Node.js**: >= 20.0.0
|
|
48
49
|
- **Chrome** 浏览器正在运行,且**已登录目标网站**(如 bilibili.com、zhihu.com、xiaohongshu.com)
|
|
49
50
|
|
|
50
51
|
> **⚠️ 重要**:大多数命令复用你的 Chrome 登录状态。运行命令前,你必须已在 Chrome 中打开目标网站并完成登录。如果获取到空数据或报错,请先检查你的浏览器登录状态。
|
|
@@ -144,34 +145,99 @@ npm install -g @jackwener/opencli@latest
|
|
|
144
145
|
|
|
145
146
|
## 内置命令
|
|
146
147
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
| 站点 | 命令 |
|
|
150
|
-
|
|
151
|
-
| **twitter** | `trending` `bookmarks` `profile` `search` `timeline` `thread` `following` `followers` `notifications` `post` `reply` `delete` `like` `article` `follow` `unfollow` `bookmark` `unbookmark`
|
|
152
|
-
| **reddit** | `hot` `frontpage` `popular` `search` `subreddit` `read` `user` `user-posts` `user-comments` `upvote` `save` `comment` `subscribe` `saved` `upvoted` |
|
|
153
|
-
| **
|
|
154
|
-
| **
|
|
155
|
-
| **codex** | `status` `send` `read` `new` `extract-diff` `model`
|
|
156
|
-
| **
|
|
157
|
-
| **
|
|
158
|
-
| **
|
|
159
|
-
| **
|
|
160
|
-
| **
|
|
161
|
-
| **
|
|
162
|
-
| **
|
|
163
|
-
| **
|
|
164
|
-
| **
|
|
165
|
-
| **
|
|
166
|
-
| **
|
|
167
|
-
| **
|
|
168
|
-
| **
|
|
169
|
-
| **
|
|
170
|
-
| **
|
|
171
|
-
| **
|
|
172
|
-
| **
|
|
173
|
-
| **
|
|
174
|
-
| **
|
|
148
|
+
运行 `opencli list` 查看完整注册表。
|
|
149
|
+
|
|
150
|
+
| 站点 | 命令 | 模式 |
|
|
151
|
+
|------|------|------|
|
|
152
|
+
| **twitter** | `trending` `bookmarks` `profile` `search` `timeline` `thread` `following` `followers` `notifications` `post` `reply` `delete` `like` `article` `follow` `unfollow` `bookmark` `unbookmark` `download` | 🔐 浏览器 |
|
|
153
|
+
| **reddit** | `hot` `frontpage` `popular` `search` `subreddit` `read` `user` `user-posts` `user-comments` `upvote` `save` `comment` `subscribe` `saved` `upvoted` | 🔐 浏览器 |
|
|
154
|
+
| **cursor** | `status` `send` `read` `new` `dump` `composer` `model` `extract-code` `ask` `screenshot` `history` `export` | 🖥️ 桌面端 |
|
|
155
|
+
| **bilibili** | `hot` `search` `me` `favorite` `history` `feed` `subtitle` `dynamic` `ranking` `following` `user-videos` `download` | 🔐 浏览器 |
|
|
156
|
+
| **codex** | `status` `send` `read` `new` `extract-diff` `model` `ask` `screenshot` `history` `export` | 🖥️ 桌面端 |
|
|
157
|
+
| **chatwise** | `status` `new` `send` `read` `ask` `model` `history` `export` `screenshot` | 🖥️ 桌面端 |
|
|
158
|
+
| **notion** | `status` `search` `read` `new` `write` `sidebar` `favorites` `export` | 🖥️ 桌面端 |
|
|
159
|
+
| **discord-app** | `status` `send` `read` `channels` `servers` `search` `members` | 🖥️ 桌面端 |
|
|
160
|
+
| **v2ex** | `hot` `latest` `topic` `daily` `me` `notifications` | 🌐 / 🔐 |
|
|
161
|
+
| **xueqiu** | `feed` `hot-stock` `hot` `search` `stock` `watchlist` | 🔐 浏览器 |
|
|
162
|
+
| **antigravity** | `status` `send` `read` `new` `evaluate` | 🖥️ 桌面端 |
|
|
163
|
+
| **chatgpt** | `status` `new` `send` `read` `ask` | 🖥️ 桌面端 |
|
|
164
|
+
| **xiaohongshu** | `search` `notifications` `feed` `me` `user` `download` | 🔐 浏览器 |
|
|
165
|
+
| **xiaoyuzhou** | `podcast` `podcast-episodes` `episode` | 🌐 公开 |
|
|
166
|
+
| **zhihu** | `hot` `search` `question` `download` | 🔐 浏览器 |
|
|
167
|
+
| **youtube** | `search` `video` `transcript` | 🔐 浏览器 |
|
|
168
|
+
| **boss** | `search` `detail` | 🔐 浏览器 |
|
|
169
|
+
| **coupang** | `search` `add-to-cart` | 🔐 浏览器 |
|
|
170
|
+
| **bbc** | `news` | 🌐 公共 API |
|
|
171
|
+
| **ctrip** | `search` | 🔐 浏览器 |
|
|
172
|
+
| **github** | `search` | 🌐 公共 API |
|
|
173
|
+
| **hackernews** | `top` | 🌐 公共 API |
|
|
174
|
+
| **linkedin** | `search` | 🔐 浏览器 |
|
|
175
|
+
| **reuters** | `search` | 🔐 浏览器 |
|
|
176
|
+
| **smzdm** | `search` | 🔐 浏览器 |
|
|
177
|
+
| **weibo** | `hot` | 🔐 浏览器 |
|
|
178
|
+
| **yahoo-finance** | `quote` | 🔐 浏览器 |
|
|
179
|
+
|
|
180
|
+
## 下载支持
|
|
181
|
+
|
|
182
|
+
OpenCLI 支持从各平台下载图片、视频和文章。
|
|
183
|
+
|
|
184
|
+
### 支持的平台
|
|
185
|
+
|
|
186
|
+
| 平台 | 内容类型 | 说明 |
|
|
187
|
+
|------|----------|------|
|
|
188
|
+
| **小红书** | 图片、视频 | 下载笔记中的所有媒体文件 |
|
|
189
|
+
| **B站** | 视频 | 需要安装 `yt-dlp` |
|
|
190
|
+
| **Twitter/X** | 图片、视频 | 从用户媒体页或单条推文下载 |
|
|
191
|
+
| **知乎** | 文章(Markdown) | 导出文章,可选下载图片到本地 |
|
|
192
|
+
|
|
193
|
+
### 前置依赖
|
|
194
|
+
|
|
195
|
+
下载流媒体平台的视频需要安装 `yt-dlp`:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
# 安装 yt-dlp
|
|
199
|
+
pip install yt-dlp
|
|
200
|
+
# 或者
|
|
201
|
+
brew install yt-dlp
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### 使用示例
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
# 下载小红书笔记中的图片/视频
|
|
208
|
+
opencli xiaohongshu download --note-id abc123 --output ./xhs
|
|
209
|
+
|
|
210
|
+
# 下载B站视频(需要 yt-dlp)
|
|
211
|
+
opencli bilibili download --bvid BV1xxx --output ./bilibili
|
|
212
|
+
opencli bilibili download --bvid BV1xxx --quality 1080p # 指定画质
|
|
213
|
+
|
|
214
|
+
# 下载 Twitter 用户的媒体
|
|
215
|
+
opencli twitter download --username elonmusk --limit 20 --output ./twitter
|
|
216
|
+
|
|
217
|
+
# 下载单条推文的媒体
|
|
218
|
+
opencli twitter download --tweet-url "https://x.com/user/status/123" --output ./twitter
|
|
219
|
+
|
|
220
|
+
# 导出知乎文章为 Markdown
|
|
221
|
+
opencli zhihu download --url "https://zhuanlan.zhihu.com/p/xxx" --output ./zhihu
|
|
222
|
+
|
|
223
|
+
# 导出文章并下载图片到本地
|
|
224
|
+
opencli zhihu download --url "https://zhuanlan.zhihu.com/p/xxx" --download-images
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Pipeline Step(用于 YAML 适配器)
|
|
228
|
+
|
|
229
|
+
`download` step 可以在 YAML 管线中使用:
|
|
230
|
+
|
|
231
|
+
```yaml
|
|
232
|
+
pipeline:
|
|
233
|
+
- fetch: https://api.example.com/media
|
|
234
|
+
- download:
|
|
235
|
+
url: ${{ item.imageUrl }}
|
|
236
|
+
dir: ./downloads
|
|
237
|
+
filename: ${{ item.title | sanitize }}.jpg
|
|
238
|
+
concurrency: 5
|
|
239
|
+
skip_existing: true
|
|
240
|
+
```
|
|
175
241
|
|
|
176
242
|
## 输出格式
|
|
177
243
|
|
|
@@ -220,7 +286,7 @@ opencli cascade https://api.example.com/data
|
|
|
220
286
|
- **返回空数据,或者报错 "Unauthorized"**
|
|
221
287
|
- Chrome 里的登录态可能已经过期(甚至被要求过滑动验证码)。请打开当前 Chrome 页面,在新标签页重新手工登录或刷新该页面。
|
|
222
288
|
- **Node API 错误 (如 parseArgs, fs 等)**
|
|
223
|
-
- 确保 Node.js 版本 `>=
|
|
289
|
+
- 确保 Node.js 版本 `>= 20`。旧版不支持我们使用的现代核心库 API。
|
|
224
290
|
- **Token 问题**
|
|
225
291
|
- 运行 `opencli doctor` 诊断所有工具的 Token 配置状态。
|
|
226
292
|
- 使用 `opencli doctor --live` 测试浏览器连通性。
|
package/dist/browser/discover.js
CHANGED
|
@@ -9,6 +9,18 @@ import * as path from 'node:path';
|
|
|
9
9
|
let _cachedMcpServerPath;
|
|
10
10
|
let _existsSync = fs.existsSync;
|
|
11
11
|
let _execSync = execSync;
|
|
12
|
+
function isSupportedMcpEntrypoint(candidate) {
|
|
13
|
+
const normalized = candidate.replace(/\\/g, '/').toLowerCase();
|
|
14
|
+
return normalized.endsWith('/@playwright/mcp/cli.js') ||
|
|
15
|
+
normalized.endsWith('/mcp-server-playwright') ||
|
|
16
|
+
normalized.endsWith('/mcp-server-playwright.js');
|
|
17
|
+
}
|
|
18
|
+
function resolveSupportedMcpPath(candidate) {
|
|
19
|
+
const trimmed = candidate?.trim();
|
|
20
|
+
if (!trimmed || !_existsSync(trimmed))
|
|
21
|
+
return null;
|
|
22
|
+
return isSupportedMcpEntrypoint(trimmed) ? trimmed : null;
|
|
23
|
+
}
|
|
12
24
|
export function resetMcpServerPathCache() {
|
|
13
25
|
_cachedMcpServerPath = undefined;
|
|
14
26
|
}
|
|
@@ -67,8 +79,9 @@ export function findMcpServerPath() {
|
|
|
67
79
|
// Try npx resolution (legacy package name)
|
|
68
80
|
try {
|
|
69
81
|
const result = _execSync('npx -y --package=@playwright/mcp which mcp-server-playwright 2>/dev/null', { encoding: 'utf-8', timeout: 10000 }).trim();
|
|
70
|
-
|
|
71
|
-
|
|
82
|
+
const resolved = resolveSupportedMcpPath(result);
|
|
83
|
+
if (resolved) {
|
|
84
|
+
_cachedMcpServerPath = resolved;
|
|
72
85
|
return _cachedMcpServerPath;
|
|
73
86
|
}
|
|
74
87
|
}
|
|
@@ -76,8 +89,9 @@ export function findMcpServerPath() {
|
|
|
76
89
|
// Try which
|
|
77
90
|
try {
|
|
78
91
|
const result = _execSync('which mcp-server-playwright 2>/dev/null', { encoding: 'utf-8', timeout: 5000 }).trim();
|
|
79
|
-
|
|
80
|
-
|
|
92
|
+
const resolved = resolveSupportedMcpPath(result);
|
|
93
|
+
if (resolved) {
|
|
94
|
+
_cachedMcpServerPath = resolved;
|
|
81
95
|
return _cachedMcpServerPath;
|
|
82
96
|
}
|
|
83
97
|
}
|
|
@@ -87,9 +101,10 @@ export function findMcpServerPath() {
|
|
|
87
101
|
if (!_existsSync(base))
|
|
88
102
|
continue;
|
|
89
103
|
try {
|
|
90
|
-
const found = _execSync(`find "${base}" -
|
|
91
|
-
|
|
92
|
-
|
|
104
|
+
const found = _execSync(`find "${base}" -type f -path "*/@playwright/mcp/cli.js" 2>/dev/null | head -1`, { encoding: 'utf-8', timeout: 5000 }).trim();
|
|
105
|
+
const resolved = resolveSupportedMcpPath(found);
|
|
106
|
+
if (resolved) {
|
|
107
|
+
_cachedMcpServerPath = resolved;
|
|
93
108
|
return _cachedMcpServerPath;
|
|
94
109
|
}
|
|
95
110
|
}
|
package/dist/browser.test.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { afterEach, describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import * as os from 'node:os';
|
|
3
|
+
import * as path from 'node:path';
|
|
2
4
|
import { PlaywrightMCP, __test__ } from './browser/index.js';
|
|
3
5
|
afterEach(() => {
|
|
4
6
|
__test__.resetMcpServerPathCache();
|
|
@@ -228,6 +230,27 @@ describe('browser helpers', () => {
|
|
|
228
230
|
});
|
|
229
231
|
}
|
|
230
232
|
});
|
|
233
|
+
it('ignores non-server playwright cli paths discovered from fallback scans', () => {
|
|
234
|
+
const wrongCli = '/root/.npm/_npx/e41f203b7505f1fb/node_modules/playwright/lib/mcp/terminal/cli.js';
|
|
235
|
+
const npxCacheBase = path.join(os.homedir(), '.npm', '_npx');
|
|
236
|
+
const existsSync = vi.fn((candidate) => {
|
|
237
|
+
const value = String(candidate);
|
|
238
|
+
return value === npxCacheBase || value === wrongCli;
|
|
239
|
+
});
|
|
240
|
+
const execSync = vi.fn((command) => {
|
|
241
|
+
if (String(command).includes('npm root -g'))
|
|
242
|
+
return '/missing/global/node_modules\n';
|
|
243
|
+
if (String(command).includes('--package=@playwright/mcp which mcp-server-playwright'))
|
|
244
|
+
return `${wrongCli}\n`;
|
|
245
|
+
if (String(command).includes('which mcp-server-playwright'))
|
|
246
|
+
return '';
|
|
247
|
+
if (String(command).includes(`find "${npxCacheBase}"`))
|
|
248
|
+
return `${wrongCli}\n`;
|
|
249
|
+
throw new Error(`unexpected command: ${String(command)}`);
|
|
250
|
+
});
|
|
251
|
+
__test__.setMcpDiscoveryTestHooks({ existsSync, execSync: execSync });
|
|
252
|
+
expect(__test__.findMcpServerPath()).toBeNull();
|
|
253
|
+
});
|
|
231
254
|
});
|
|
232
255
|
describe('PlaywrightMCP state', () => {
|
|
233
256
|
it('transitions to closed after close()', async () => {
|
package/dist/build-manifest.d.ts
CHANGED
|
@@ -8,4 +8,30 @@
|
|
|
8
8
|
* Usage: npx tsx src/build-manifest.ts
|
|
9
9
|
* Output: dist/cli-manifest.json
|
|
10
10
|
*/
|
|
11
|
+
interface ManifestEntry {
|
|
12
|
+
site: string;
|
|
13
|
+
name: string;
|
|
14
|
+
description: string;
|
|
15
|
+
domain?: string;
|
|
16
|
+
strategy: string;
|
|
17
|
+
browser: boolean;
|
|
18
|
+
args: Array<{
|
|
19
|
+
name: string;
|
|
20
|
+
type?: string;
|
|
21
|
+
default?: any;
|
|
22
|
+
required?: boolean;
|
|
23
|
+
positional?: boolean;
|
|
24
|
+
help?: string;
|
|
25
|
+
choices?: string[];
|
|
26
|
+
}>;
|
|
27
|
+
columns?: string[];
|
|
28
|
+
pipeline?: any[];
|
|
29
|
+
timeout?: number;
|
|
30
|
+
/** 'yaml' or 'ts' — determines how executeCommand loads the handler */
|
|
31
|
+
type: 'yaml' | 'ts';
|
|
32
|
+
/** Relative path from clis/ dir, e.g. 'bilibili/hot.yaml' or 'bilibili/search.js' */
|
|
33
|
+
modulePath?: string;
|
|
34
|
+
}
|
|
35
|
+
export declare function parseTsArgsBlock(argsBlock: string): ManifestEntry['args'];
|
|
36
|
+
export declare function buildManifest(): ManifestEntry[];
|
|
11
37
|
export {};
|