thepopebot 1.2.74 → 1.2.75-beta.2
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/README.md +11 -0
- package/api/CLAUDE.md +2 -0
- package/api/index.js +95 -3
- package/bin/cli.js +1 -1
- package/bin/managed-paths.js +1 -1
- package/bin/sync.js +7 -2
- package/config/instrumentation.js +4 -0
- package/lib/chat/actions.js +4 -4
- package/lib/chat/components/chat-input.js +2 -2
- package/lib/chat/components/chat-input.jsx +2 -2
- package/lib/chat/components/settings-chat-page.js +41 -37
- package/lib/chat/components/settings-chat-page.jsx +39 -37
- package/lib/chat/components/settings-jobs-page.js +68 -10
- package/lib/chat/components/settings-jobs-page.jsx +99 -34
- package/lib/code/code-page.js +2 -1
- package/lib/code/code-page.jsx +2 -1
- package/lib/code/terminal-view.js +6 -3
- package/lib/code/terminal-view.jsx +6 -3
- package/lib/db/api-keys.js +35 -2
- package/lib/db/config.js +40 -4
- package/lib/maintenance.js +35 -0
- package/lib/oauth/helper.js +34 -0
- package/lib/tools/create-agent-job.js +3 -0
- package/lib/tools/docker.js +12 -5
- package/package.json +3 -2
- package/templates/docker-compose.custom.yml +1 -0
- package/templates/docker-compose.litellm.yml +1 -0
- package/templates/docker-compose.yml +2 -0
- package/templates/skills/agent-job-secrets/SKILL.md +25 -0
- package/templates/skills/agent-job-secrets/agent-job-secrets.js +66 -0
- package/templates/skills/playwright-cli/SKILL.md +294 -0
- package/templates/skills/brave-search/SKILL.md +0 -79
- package/templates/skills/brave-search/content.js +0 -86
- package/templates/skills/brave-search/package-lock.json +0 -621
- package/templates/skills/brave-search/package.json +0 -14
- package/templates/skills/brave-search/search.js +0 -199
- package/templates/skills/browser-tools/SKILL.md +0 -196
- package/templates/skills/browser-tools/browser-content.js +0 -103
- package/templates/skills/browser-tools/browser-cookies.js +0 -35
- package/templates/skills/browser-tools/browser-eval.js +0 -53
- package/templates/skills/browser-tools/browser-hn-scraper.js +0 -108
- package/templates/skills/browser-tools/browser-nav.js +0 -44
- package/templates/skills/browser-tools/browser-pick.js +0 -162
- package/templates/skills/browser-tools/browser-screenshot.js +0 -34
- package/templates/skills/browser-tools/browser-start.js +0 -87
- package/templates/skills/browser-tools/package-lock.json +0 -2556
- package/templates/skills/browser-tools/package.json +0 -19
- package/templates/skills/get-secret/SKILL.md +0 -34
- package/templates/skills/get-secret/get-secret.js +0 -33
- package/templates/skills/google-docs/SKILL.md +0 -23
- package/templates/skills/google-docs/create.sh +0 -69
- package/templates/skills/google-drive/SKILL.md +0 -47
- package/templates/skills/google-drive/delete.sh +0 -47
- package/templates/skills/google-drive/download.sh +0 -50
- package/templates/skills/google-drive/list.sh +0 -41
- package/templates/skills/google-drive/upload.sh +0 -76
- package/templates/skills/kie-ai/SKILL.md +0 -38
- package/templates/skills/kie-ai/generate-image.sh +0 -77
- package/templates/skills/kie-ai/generate-video.sh +0 -69
- package/templates/skills/youtube-transcript/SKILL.md +0 -41
- package/templates/skills/youtube-transcript/package-lock.json +0 -24
- package/templates/skills/youtube-transcript/package.json +0 -8
- package/templates/skills/youtube-transcript/transcript.js +0 -84
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agent-job-secrets
|
|
3
|
+
description: List, get, or update agent secrets. Use get for OAuth credentials (auto-refreshed on every call). Use set to persist updated credentials back to the event handler.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Usage
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
# List available secrets (null = must fetch, plain = already in env)
|
|
10
|
+
node skills/agent-job-secrets/agent-job-secrets.js
|
|
11
|
+
|
|
12
|
+
# Get a secret value (OAuth credentials are auto-refreshed)
|
|
13
|
+
node skills/agent-job-secrets/agent-job-secrets.js get MY_CREDENTIALS
|
|
14
|
+
|
|
15
|
+
# Set/update a secret (plain string or piped value)
|
|
16
|
+
node skills/agent-job-secrets/agent-job-secrets.js set MY_KEY "value"
|
|
17
|
+
echo "$UPDATED_CREDENTIALS" | node skills/agent-job-secrets/agent-job-secrets.js set MY_KEY
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Notes
|
|
21
|
+
|
|
22
|
+
- `AGENT_JOB_TOKEN` and `APP_URL` are injected automatically — no setup required
|
|
23
|
+
- OAuth credentials show as `null` in the list and must be fetched via `get`
|
|
24
|
+
- `get` on an OAuth credential refreshes it and persists the updated token immediately
|
|
25
|
+
- Plain secrets are available directly as env vars (e.g. `echo $MY_KEY`)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
|
+
|
|
4
|
+
const [cmd, key, inlineValue] = process.argv.slice(2);
|
|
5
|
+
|
|
6
|
+
// Default to list
|
|
7
|
+
if (!cmd || cmd === 'list') {
|
|
8
|
+
const secretsJson = process.env.AGENT_JOB_SECRETS;
|
|
9
|
+
if (!secretsJson) {
|
|
10
|
+
console.log('No agent secrets configured.');
|
|
11
|
+
process.exit(0);
|
|
12
|
+
}
|
|
13
|
+
const secrets = JSON.parse(secretsJson);
|
|
14
|
+
const keys = Object.keys(secrets);
|
|
15
|
+
if (keys.length === 0) {
|
|
16
|
+
console.log('No agent secrets configured.');
|
|
17
|
+
} else {
|
|
18
|
+
console.log('Available secrets:');
|
|
19
|
+
keys.forEach(k => {
|
|
20
|
+
const fetchRequired = secrets[k] === null;
|
|
21
|
+
console.log(` - ${k}${fetchRequired ? ' (fetch required: use get)' : ''}`);
|
|
22
|
+
});
|
|
23
|
+
console.log('\nTo get a value: agent-job-secrets.js get KEY_NAME');
|
|
24
|
+
}
|
|
25
|
+
process.exit(0);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const apiKey = process.env.AGENT_JOB_TOKEN;
|
|
29
|
+
const appUrl = process.env.APP_URL;
|
|
30
|
+
if (!apiKey) { console.error('AGENT_JOB_TOKEN not available'); process.exit(1); }
|
|
31
|
+
if (!appUrl) { console.error('APP_URL not available'); process.exit(1); }
|
|
32
|
+
|
|
33
|
+
if (cmd === 'get') {
|
|
34
|
+
if (!key) { console.error('Usage: agent-job-secrets.js get KEY_NAME'); process.exit(1); }
|
|
35
|
+
const res = await fetch(`${appUrl}/api/get-agent-job-secret?key=${encodeURIComponent(key)}`, {
|
|
36
|
+
headers: { 'x-api-key': apiKey },
|
|
37
|
+
});
|
|
38
|
+
const json = await res.json();
|
|
39
|
+
if (!res.ok || json.error) { console.error('Failed:', json.error || res.status); process.exit(1); }
|
|
40
|
+
console.log(json.value);
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (cmd === 'set') {
|
|
45
|
+
if (!key) {
|
|
46
|
+
console.error('Usage: agent-job-secrets.js set KEY_NAME [value]');
|
|
47
|
+
console.error(' echo "value" | agent-job-secrets.js set KEY_NAME');
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
let value = inlineValue;
|
|
51
|
+
if (value === undefined) {
|
|
52
|
+
value = readFileSync('/dev/stdin', 'utf8').trim();
|
|
53
|
+
}
|
|
54
|
+
const res = await fetch(`${appUrl}/api/set-agent-job-secret`, {
|
|
55
|
+
method: 'POST',
|
|
56
|
+
headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey },
|
|
57
|
+
body: JSON.stringify({ key, value }),
|
|
58
|
+
});
|
|
59
|
+
const json = await res.json();
|
|
60
|
+
if (!res.ok || json.error) { console.error('Failed:', json.error || res.status); process.exit(1); }
|
|
61
|
+
console.log(`Secret "${key}" updated.`);
|
|
62
|
+
process.exit(0);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.error(`Unknown command: ${cmd}`);
|
|
66
|
+
process.exit(1);
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: playwright-cli
|
|
3
|
+
description: Automate browser interactions, test web pages and work with Playwright tests.
|
|
4
|
+
allowed-tools: Bash(playwright-cli:*) Bash(npx:*) Bash(npm:*)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Browser Automation with playwright-cli
|
|
8
|
+
|
|
9
|
+
## Quick start
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# open new browser
|
|
13
|
+
playwright-cli open
|
|
14
|
+
# navigate to a page
|
|
15
|
+
playwright-cli goto https://playwright.dev
|
|
16
|
+
# interact with the page using refs from the snapshot
|
|
17
|
+
playwright-cli click e15
|
|
18
|
+
playwright-cli type "page.click"
|
|
19
|
+
playwright-cli press Enter
|
|
20
|
+
# take a screenshot (rarely used, as snapshot is more common)
|
|
21
|
+
playwright-cli screenshot
|
|
22
|
+
# close the browser
|
|
23
|
+
playwright-cli close
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Commands
|
|
27
|
+
|
|
28
|
+
### Core
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
playwright-cli open
|
|
32
|
+
# open and navigate right away
|
|
33
|
+
playwright-cli open https://example.com/
|
|
34
|
+
playwright-cli goto https://playwright.dev
|
|
35
|
+
playwright-cli type "search query"
|
|
36
|
+
playwright-cli click e3
|
|
37
|
+
playwright-cli dblclick e7
|
|
38
|
+
# --submit presses Enter after filling the element
|
|
39
|
+
playwright-cli fill e5 "user@example.com" --submit
|
|
40
|
+
playwright-cli drag e2 e8
|
|
41
|
+
playwright-cli hover e4
|
|
42
|
+
playwright-cli select e9 "option-value"
|
|
43
|
+
playwright-cli upload ./document.pdf
|
|
44
|
+
playwright-cli check e12
|
|
45
|
+
playwright-cli uncheck e12
|
|
46
|
+
playwright-cli snapshot
|
|
47
|
+
playwright-cli eval "document.title"
|
|
48
|
+
playwright-cli eval "el => el.textContent" e5
|
|
49
|
+
# get element id, class, or any attribute not visible in the snapshot
|
|
50
|
+
playwright-cli eval "el => el.id" e5
|
|
51
|
+
playwright-cli eval "el => el.getAttribute('data-testid')" e5
|
|
52
|
+
playwright-cli dialog-accept
|
|
53
|
+
playwright-cli dialog-accept "confirmation text"
|
|
54
|
+
playwright-cli dialog-dismiss
|
|
55
|
+
playwright-cli resize 1920 1080
|
|
56
|
+
playwright-cli close
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Navigation
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
playwright-cli go-back
|
|
63
|
+
playwright-cli go-forward
|
|
64
|
+
playwright-cli reload
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Keyboard
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
playwright-cli press Enter
|
|
71
|
+
playwright-cli press ArrowDown
|
|
72
|
+
playwright-cli keydown Shift
|
|
73
|
+
playwright-cli keyup Shift
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Mouse
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
playwright-cli mousemove 150 300
|
|
80
|
+
playwright-cli mousedown
|
|
81
|
+
playwright-cli mousedown right
|
|
82
|
+
playwright-cli mouseup
|
|
83
|
+
playwright-cli mouseup right
|
|
84
|
+
playwright-cli mousewheel 0 100
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Save as
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
playwright-cli screenshot
|
|
91
|
+
playwright-cli screenshot e5
|
|
92
|
+
playwright-cli screenshot --filename=page.png
|
|
93
|
+
playwright-cli pdf --filename=page.pdf
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Tabs
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
playwright-cli tab-list
|
|
100
|
+
playwright-cli tab-new
|
|
101
|
+
playwright-cli tab-new https://example.com/page
|
|
102
|
+
playwright-cli tab-close
|
|
103
|
+
playwright-cli tab-close 2
|
|
104
|
+
playwright-cli tab-select 0
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Storage
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
playwright-cli state-save
|
|
111
|
+
playwright-cli state-save auth.json
|
|
112
|
+
playwright-cli state-load auth.json
|
|
113
|
+
|
|
114
|
+
# Cookies
|
|
115
|
+
playwright-cli cookie-list
|
|
116
|
+
playwright-cli cookie-list --domain=example.com
|
|
117
|
+
playwright-cli cookie-get session_id
|
|
118
|
+
playwright-cli cookie-set session_id abc123
|
|
119
|
+
playwright-cli cookie-set session_id abc123 --domain=example.com --httpOnly --secure
|
|
120
|
+
playwright-cli cookie-delete session_id
|
|
121
|
+
playwright-cli cookie-clear
|
|
122
|
+
|
|
123
|
+
# LocalStorage
|
|
124
|
+
playwright-cli localstorage-list
|
|
125
|
+
playwright-cli localstorage-get theme
|
|
126
|
+
playwright-cli localstorage-set theme dark
|
|
127
|
+
playwright-cli localstorage-delete theme
|
|
128
|
+
playwright-cli localstorage-clear
|
|
129
|
+
|
|
130
|
+
# SessionStorage
|
|
131
|
+
playwright-cli sessionstorage-list
|
|
132
|
+
playwright-cli sessionstorage-get step
|
|
133
|
+
playwright-cli sessionstorage-set step 3
|
|
134
|
+
playwright-cli sessionstorage-delete step
|
|
135
|
+
playwright-cli sessionstorage-clear
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Network
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
playwright-cli route "**/*.jpg" --status=404
|
|
142
|
+
playwright-cli route "https://api.example.com/**" --body='{"mock": true}'
|
|
143
|
+
playwright-cli route-list
|
|
144
|
+
playwright-cli unroute "**/*.jpg"
|
|
145
|
+
playwright-cli unroute
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### DevTools
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
playwright-cli console
|
|
152
|
+
playwright-cli console warning
|
|
153
|
+
playwright-cli network
|
|
154
|
+
playwright-cli run-code "async page => await page.context().grantPermissions(['geolocation'])"
|
|
155
|
+
playwright-cli run-code --filename=script.js
|
|
156
|
+
playwright-cli tracing-start
|
|
157
|
+
playwright-cli tracing-stop
|
|
158
|
+
playwright-cli video-start video.webm
|
|
159
|
+
playwright-cli video-chapter "Chapter Title" --description="Details" --duration=2000
|
|
160
|
+
playwright-cli video-stop
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Open parameters
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
# Use specific browser when creating session
|
|
167
|
+
playwright-cli open --browser=chrome
|
|
168
|
+
playwright-cli open --browser=firefox
|
|
169
|
+
playwright-cli open --browser=webkit
|
|
170
|
+
playwright-cli open --browser=msedge
|
|
171
|
+
# Connect to browser via extension
|
|
172
|
+
playwright-cli open --extension
|
|
173
|
+
|
|
174
|
+
# Use persistent profile (by default profile is in-memory)
|
|
175
|
+
playwright-cli open --persistent
|
|
176
|
+
# Use persistent profile with custom directory
|
|
177
|
+
playwright-cli open --profile=/path/to/profile
|
|
178
|
+
|
|
179
|
+
# Start with config file
|
|
180
|
+
playwright-cli open --config=my-config.json
|
|
181
|
+
|
|
182
|
+
# Close the browser
|
|
183
|
+
playwright-cli close
|
|
184
|
+
# Delete user data for the default session
|
|
185
|
+
playwright-cli delete-data
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Snapshots
|
|
189
|
+
|
|
190
|
+
After each command, playwright-cli provides a snapshot of the current browser state.
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
> playwright-cli goto https://example.com
|
|
194
|
+
### Page
|
|
195
|
+
- Page URL: https://example.com/
|
|
196
|
+
- Page Title: Example Domain
|
|
197
|
+
### Snapshot
|
|
198
|
+
[Snapshot](.playwright-cli/page-2026-02-14T19-22-42-679Z.yml)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
You can also take a snapshot on demand using `playwright-cli snapshot` command.
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
# default - save to a file with timestamp-based name
|
|
205
|
+
playwright-cli snapshot
|
|
206
|
+
|
|
207
|
+
# save to file, use when snapshot is a part of the workflow result
|
|
208
|
+
playwright-cli snapshot --filename=after-click.yaml
|
|
209
|
+
|
|
210
|
+
# snapshot an element instead of the whole page
|
|
211
|
+
playwright-cli snapshot "#main"
|
|
212
|
+
|
|
213
|
+
# limit snapshot depth for efficiency, take a partial snapshot afterwards
|
|
214
|
+
playwright-cli snapshot --depth=4
|
|
215
|
+
playwright-cli snapshot e34
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Targeting elements
|
|
219
|
+
|
|
220
|
+
By default, use refs from the snapshot to interact with page elements.
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# get snapshot with refs
|
|
224
|
+
playwright-cli snapshot
|
|
225
|
+
|
|
226
|
+
# interact using a ref
|
|
227
|
+
playwright-cli click e15
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
You can also use css selectors or Playwright locators.
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
# css selector
|
|
234
|
+
playwright-cli click "#main > button.submit"
|
|
235
|
+
|
|
236
|
+
# role locator
|
|
237
|
+
playwright-cli click "getByRole('button', { name: 'Submit' })"
|
|
238
|
+
|
|
239
|
+
# test id
|
|
240
|
+
playwright-cli click "getByTestId('submit-button')"
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Browser Sessions
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
# create new browser session named "mysession" with persistent profile
|
|
247
|
+
playwright-cli -s=mysession open example.com --persistent
|
|
248
|
+
# same with manually specified profile directory (use when requested explicitly)
|
|
249
|
+
playwright-cli -s=mysession open example.com --profile=/path/to/profile
|
|
250
|
+
playwright-cli -s=mysession click e6
|
|
251
|
+
playwright-cli -s=mysession close # stop a named browser
|
|
252
|
+
playwright-cli -s=mysession delete-data # delete user data for persistent session
|
|
253
|
+
|
|
254
|
+
playwright-cli list
|
|
255
|
+
# Close all browsers
|
|
256
|
+
playwright-cli close-all
|
|
257
|
+
# Forcefully kill all browser processes
|
|
258
|
+
playwright-cli kill-all
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Example: Form submission
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
playwright-cli open https://example.com/form
|
|
265
|
+
playwright-cli snapshot
|
|
266
|
+
|
|
267
|
+
playwright-cli fill e1 "user@example.com"
|
|
268
|
+
playwright-cli fill e2 "password123"
|
|
269
|
+
playwright-cli click e3
|
|
270
|
+
playwright-cli snapshot
|
|
271
|
+
playwright-cli close
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Example: Multi-tab workflow
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
playwright-cli open https://example.com
|
|
278
|
+
playwright-cli tab-new https://example.com/other
|
|
279
|
+
playwright-cli tab-list
|
|
280
|
+
playwright-cli tab-select 0
|
|
281
|
+
playwright-cli snapshot
|
|
282
|
+
playwright-cli close
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Example: Debugging with DevTools
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
playwright-cli open https://example.com
|
|
289
|
+
playwright-cli click e4
|
|
290
|
+
playwright-cli fill e7 "test"
|
|
291
|
+
playwright-cli console
|
|
292
|
+
playwright-cli network
|
|
293
|
+
playwright-cli close
|
|
294
|
+
```
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: brave-search
|
|
3
|
-
description: Web search and content extraction via Brave Search API. Use for searching documentation, facts, or any web content. Lightweight, no browser required.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Brave Search
|
|
7
|
-
|
|
8
|
-
Web search and content extraction using the official Brave Search API. No browser required.
|
|
9
|
-
|
|
10
|
-
## Setup
|
|
11
|
-
|
|
12
|
-
Requires a Brave Search API account with a free subscription. A credit card is required to create the free subscription (you won't be charged).
|
|
13
|
-
|
|
14
|
-
1. Create an account at https://api-dashboard.search.brave.com/register
|
|
15
|
-
2. Create a "Free AI" subscription
|
|
16
|
-
3. Create an API key for the subscription
|
|
17
|
-
4. Add to your shell profile (`~/.profile` or `~/.zprofile` for zsh):
|
|
18
|
-
```bash
|
|
19
|
-
export BRAVE_API_KEY="your-api-key-here"
|
|
20
|
-
```
|
|
21
|
-
5. Install dependencies (run once):
|
|
22
|
-
```bash
|
|
23
|
-
cd skills/brave-search
|
|
24
|
-
npm install
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Search
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
skills/brave-search/search.js "query" # Basic search (5 results)
|
|
31
|
-
skills/brave-search/search.js "query" -n 10 # More results (max 20)
|
|
32
|
-
skills/brave-search/search.js "query" --content # Include page content as markdown
|
|
33
|
-
skills/brave-search/search.js "query" --freshness pw # Results from last week
|
|
34
|
-
skills/brave-search/search.js "query" --freshness 2024-01-01to2024-06-30 # Date range
|
|
35
|
-
skills/brave-search/search.js "query" --country DE # Results from Germany
|
|
36
|
-
skills/brave-search/search.js "query" -n 3 --content # Combined options
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### Options
|
|
40
|
-
|
|
41
|
-
- `-n <num>` - Number of results (default: 5, max: 20)
|
|
42
|
-
- `--content` - Fetch and include page content as markdown
|
|
43
|
-
- `--country <code>` - Two-letter country code (default: US)
|
|
44
|
-
- `--freshness <period>` - Filter by time:
|
|
45
|
-
- `pd` - Past day (24 hours)
|
|
46
|
-
- `pw` - Past week
|
|
47
|
-
- `pm` - Past month
|
|
48
|
-
- `py` - Past year
|
|
49
|
-
- `YYYY-MM-DDtoYYYY-MM-DD` - Custom date range
|
|
50
|
-
|
|
51
|
-
## Extract Page Content
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
skills/brave-search/content.js https://example.com/article
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Fetches a URL and extracts readable content as markdown.
|
|
58
|
-
|
|
59
|
-
## Output Format
|
|
60
|
-
|
|
61
|
-
```
|
|
62
|
-
--- Result 1 ---
|
|
63
|
-
Title: Page Title
|
|
64
|
-
Link: https://example.com/page
|
|
65
|
-
Age: 2 days ago
|
|
66
|
-
Snippet: Description from search results
|
|
67
|
-
Content: (if --content flag used)
|
|
68
|
-
Markdown content extracted from the page...
|
|
69
|
-
|
|
70
|
-
--- Result 2 ---
|
|
71
|
-
...
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
## When to Use
|
|
75
|
-
|
|
76
|
-
- Searching for documentation or API references
|
|
77
|
-
- Looking up facts or current information
|
|
78
|
-
- Fetching content from specific URLs
|
|
79
|
-
- Any task requiring web search without interactive browsing
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { Readability } from "@mozilla/readability";
|
|
4
|
-
import { JSDOM } from "jsdom";
|
|
5
|
-
import TurndownService from "turndown";
|
|
6
|
-
import { gfm } from "turndown-plugin-gfm";
|
|
7
|
-
|
|
8
|
-
const url = process.argv[2];
|
|
9
|
-
|
|
10
|
-
if (!url) {
|
|
11
|
-
console.log("Usage: content.js <url>");
|
|
12
|
-
console.log("\nExtracts readable content from a webpage as markdown.");
|
|
13
|
-
console.log("\nExamples:");
|
|
14
|
-
console.log(" content.js https://example.com/article");
|
|
15
|
-
console.log(" content.js https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html");
|
|
16
|
-
process.exit(1);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function htmlToMarkdown(html) {
|
|
20
|
-
const turndown = new TurndownService({ headingStyle: "atx", codeBlockStyle: "fenced" });
|
|
21
|
-
turndown.use(gfm);
|
|
22
|
-
turndown.addRule("removeEmptyLinks", {
|
|
23
|
-
filter: (node) => node.nodeName === "A" && !node.textContent?.trim(),
|
|
24
|
-
replacement: () => "",
|
|
25
|
-
});
|
|
26
|
-
return turndown
|
|
27
|
-
.turndown(html)
|
|
28
|
-
.replace(/\[\\?\[\s*\\?\]\]\([^)]*\)/g, "")
|
|
29
|
-
.replace(/ +/g, " ")
|
|
30
|
-
.replace(/\s+,/g, ",")
|
|
31
|
-
.replace(/\s+\./g, ".")
|
|
32
|
-
.replace(/\n{3,}/g, "\n\n")
|
|
33
|
-
.trim();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
try {
|
|
37
|
-
const response = await fetch(url, {
|
|
38
|
-
headers: {
|
|
39
|
-
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
|
40
|
-
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
41
|
-
"Accept-Language": "en-US,en;q=0.9",
|
|
42
|
-
},
|
|
43
|
-
signal: AbortSignal.timeout(15000),
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
if (!response.ok) {
|
|
47
|
-
console.error(`HTTP ${response.status}: ${response.statusText}`);
|
|
48
|
-
process.exit(1);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const html = await response.text();
|
|
52
|
-
const dom = new JSDOM(html, { url });
|
|
53
|
-
const reader = new Readability(dom.window.document);
|
|
54
|
-
const article = reader.parse();
|
|
55
|
-
|
|
56
|
-
if (article && article.content) {
|
|
57
|
-
if (article.title) {
|
|
58
|
-
console.log(`# ${article.title}\n`);
|
|
59
|
-
}
|
|
60
|
-
console.log(htmlToMarkdown(article.content));
|
|
61
|
-
process.exit(0);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Fallback: try to extract main content
|
|
65
|
-
const fallbackDoc = new JSDOM(html, { url });
|
|
66
|
-
const body = fallbackDoc.window.document;
|
|
67
|
-
body.querySelectorAll("script, style, noscript, nav, header, footer, aside").forEach(el => el.remove());
|
|
68
|
-
|
|
69
|
-
const title = body.querySelector("title")?.textContent?.trim();
|
|
70
|
-
const main = body.querySelector("main, article, [role='main'], .content, #content") || body.body;
|
|
71
|
-
|
|
72
|
-
if (title) {
|
|
73
|
-
console.log(`# ${title}\n`);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const text = main?.innerHTML || "";
|
|
77
|
-
if (text.trim().length > 100) {
|
|
78
|
-
console.log(htmlToMarkdown(text));
|
|
79
|
-
} else {
|
|
80
|
-
console.error("Could not extract readable content from this page.");
|
|
81
|
-
process.exit(1);
|
|
82
|
-
}
|
|
83
|
-
} catch (e) {
|
|
84
|
-
console.error(`Error: ${e.message}`);
|
|
85
|
-
process.exit(1);
|
|
86
|
-
}
|