fastbrowser_cli 1.0.35 → 1.0.39
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 +26 -5
- package/dist/contribs/_shared/fastbrowser_helper.d.ts +13 -0
- package/dist/contribs/_shared/fastbrowser_helper.d.ts.map +1 -0
- package/dist/contribs/_shared/fastbrowser_helper.js +39 -0
- package/dist/contribs/_shared/fastbrowser_helper.js.map +1 -0
- package/dist/contribs/linkedin_cli/src/cli.d.ts +3 -0
- package/dist/contribs/linkedin_cli/src/cli.d.ts.map +1 -0
- package/dist/contribs/linkedin_cli/src/cli.js +299 -0
- package/dist/contribs/linkedin_cli/src/cli.js.map +1 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_profile_helper.d.ts +73 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_profile_helper.d.ts.map +1 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_profile_helper.js +866 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_profile_helper.js.map +1 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_recent_posts_helper.d.ts +61 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_recent_posts_helper.d.ts.map +1 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_recent_posts_helper.js +885 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_recent_posts_helper.js.map +1 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_thread_helper.d.ts +11 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_thread_helper.d.ts.map +1 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_thread_helper.js +145 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_thread_helper.js.map +1 -0
- package/dist/contribs/twitter_cli/src/cli.d.ts +3 -0
- package/dist/contribs/twitter_cli/src/cli.d.ts.map +1 -0
- package/dist/contribs/twitter_cli/src/cli.js +273 -0
- package/dist/contribs/twitter_cli/src/cli.js.map +1 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_profile_helper.d.ts +28 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_profile_helper.d.ts.map +1 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_profile_helper.js +274 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_profile_helper.js.map +1 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_recent_posts_helper.d.ts +43 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_recent_posts_helper.d.ts.map +1 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_recent_posts_helper.js +519 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_recent_posts_helper.js.map +1 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_thread_helper.d.ts +11 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_thread_helper.d.ts.map +1 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_thread_helper.js +213 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_thread_helper.js.map +1 -0
- package/dist/fastbrowser_cli/fastbrowser_cli.js +43 -0
- package/dist/fastbrowser_cli/fastbrowser_cli.js.map +1 -1
- package/dist/fastbrowser_httpd/libs/tool-schemas.d.ts +4 -0
- package/dist/fastbrowser_httpd/libs/tool-schemas.d.ts.map +1 -1
- package/dist/fastbrowser_httpd/libs/tool-schemas.js +4 -0
- package/dist/fastbrowser_httpd/libs/tool-schemas.js.map +1 -1
- package/dist/fastbrowser_mcp/fastbrowser_mcp.js +36 -2
- package/dist/fastbrowser_mcp/fastbrowser_mcp.js.map +1 -1
- package/dist/fastbrowser_mcp/libs/mcp_target_helper.d.ts +2 -0
- package/dist/fastbrowser_mcp/libs/mcp_target_helper.d.ts.map +1 -1
- package/dist/fastbrowser_mcp/libs/mcp_target_helper.js +12 -0
- package/dist/fastbrowser_mcp/libs/mcp_target_helper.js.map +1 -1
- package/dist/fastbrowser_mcp/libs/response_formatter.d.ts +1 -0
- package/dist/fastbrowser_mcp/libs/response_formatter.d.ts.map +1 -1
- package/dist/fastbrowser_mcp/libs/response_formatter.js +27 -0
- package/dist/fastbrowser_mcp/libs/response_formatter.js.map +1 -1
- package/dist/shared/fastbrowser_helper.d.ts +13 -0
- package/dist/shared/fastbrowser_helper.d.ts.map +1 -0
- package/dist/shared/fastbrowser_helper.js +39 -0
- package/dist/shared/fastbrowser_helper.js.map +1 -0
- package/examples/linkedin_cli_TOREMOVE/README.md +7 -0
- package/examples/linkedin_cli_TOREMOVE/linkedin_dm.sh +40 -0
- package/examples/linkedin_cli_TOREMOVE/linkedin_dm.ts +326 -0
- package/examples/linkedin_cli_TOREMOVE/linkedin_dm_messages.ts +279 -0
- package/examples/linkedin_cli_TOREMOVE/linkedin_full_cycle.sh +5 -0
- package/examples/{linkedin_cli/linked_post.sh → linkedin_cli_TOREMOVE/linkedin_post.sh} +3 -0
- package/examples/linkedin_cli_TOREMOVE/message_thread.a11y.txt +252 -0
- package/examples/whatsapp/whatapp.a11y.txt +1521 -0
- package/examples/whatsapp/whatsapp.sh +10 -0
- package/listitem +7 -0
- package/package.json +7 -3
- package/skills/fastbrowser/SKILL.md +116 -29
- package/src/contribs/_shared/fastbrowser_helper.ts +49 -0
- package/src/contribs/linkedin_cli/README.md +80 -0
- package/src/contribs/linkedin_cli/data/linkedin_posts_jeromeetienne.a11y.txt +2364 -0
- package/src/contribs/linkedin_cli/data/linkedin_posts_jontwigge.a11y.txt +2740 -0
- package/src/contribs/linkedin_cli/data/linkedin_posts_julien_guezennec.a11y.txt +2073 -0
- package/src/contribs/linkedin_cli/data/linkedin_profile_jeromeetienne.a11y.txt +1863 -0
- package/src/contribs/linkedin_cli/data/linkedin_profile_jontwigge.a11y.txt +1738 -0
- package/src/contribs/linkedin_cli/data/linkedin_profile_julien_guezennec.a11y.txt +2182 -0
- package/src/contribs/linkedin_cli/src/cli.ts +345 -0
- package/src/contribs/linkedin_cli/src/libs/linkedin_profile_helper.ts +964 -0
- package/src/contribs/linkedin_cli/src/libs/linkedin_recent_posts_helper.ts +982 -0
- package/src/contribs/linkedin_cli/src/libs/linkedin_thread_helper.ts +171 -0
- package/src/contribs/twitter_cli/README.md +79 -0
- package/src/contribs/twitter_cli/data/twitter_chat.a11y.txt +215 -0
- package/src/contribs/twitter_cli/data/twitter_home.a11y.txt +467 -0
- package/src/contribs/twitter_cli/data/twitter_profile.a11y.txt +418 -0
- package/src/contribs/twitter_cli/data/twitter_profile_jontwigge.a11y.txt +484 -0
- package/src/contribs/twitter_cli/data/twitter_profile_molokoloco.a11y.txt +483 -0
- package/src/contribs/twitter_cli/src/cli.ts +315 -0
- package/src/contribs/twitter_cli/src/libs/twitter_profile_helper.ts +328 -0
- package/src/contribs/twitter_cli/src/libs/twitter_recent_posts_helper.ts +607 -0
- package/src/contribs/twitter_cli/src/libs/twitter_thread_helper.ts +240 -0
- package/src/fastbrowser_cli/fastbrowser_cli.ts +51 -0
- package/src/fastbrowser_httpd/libs/tool-schemas.ts +6 -0
- package/src/fastbrowser_mcp/fastbrowser_mcp.ts +46 -3
- package/src/fastbrowser_mcp/libs/mcp_target_helper.ts +11 -0
- package/src/fastbrowser_mcp/libs/response_formatter.ts +29 -0
- package/src/shared/fastbrowser_helper.ts +49 -0
- package/tsconfig.json +1 -1
- package/examples/linkedin_cli/linked_dm.sh +0 -19
- package/examples/mcp_client_playwright.ts +0 -34
- /package/examples/{linkedin_cli → linkedin_cli_TOREMOVE}/linkedin.snapshot.txt +0 -0
- /package/examples/{twitter_cli → twitter_cli_TOREMOVE}/twitter_post.sh +0 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/bin/env bash
|
|
2
|
+
|
|
3
|
+
# restart the server
|
|
4
|
+
NODE_OPTIONS='' NPM_CONFIG_LOGLEVEL=silent npm run dev:cli -- server restart
|
|
5
|
+
|
|
6
|
+
# navigate to whatsapp web
|
|
7
|
+
NODE_OPTIONS='' NPM_CONFIG_LOGLEVEL=silent npm run dev:cli -- navigate_page --url https://web.whatsapp.com/
|
|
8
|
+
|
|
9
|
+
# List all conversations in the chat list
|
|
10
|
+
NODE_OPTIONS='' NPM_CONFIG_LOGLEVEL=silent npm run dev:cli -- query_selectors -s 'grid[name="Chat list"] > row' -a
|
package/listitem
ADDED
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastbrowser_cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.39",
|
|
4
4
|
"description": "A CLI tool for FastBrowser, providing commands to interact with the FastBrowser MCP (Model Context Protocol) server and perform various browser automation tasks.",
|
|
5
5
|
"main": "dist/fastbrowser_cli/fastbrowser_cli.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"fastbrowser_cli": "./dist/fastbrowser_cli/fastbrowser_cli.js",
|
|
8
|
-
"fastbrowser_mcp": "./dist/fastbrowser_mcp/fastbrowser_mcp.js"
|
|
8
|
+
"fastbrowser_mcp": "./dist/fastbrowser_mcp/fastbrowser_mcp.js",
|
|
9
|
+
"linkedin_cli": "./dist/contribs/linkedin_cli/src/cli.js",
|
|
10
|
+
"twitter_cli": "./dist/contribs/twitter_cli/src/cli.js"
|
|
9
11
|
},
|
|
10
12
|
"keywords": [],
|
|
11
13
|
"author": "",
|
|
@@ -30,7 +32,7 @@
|
|
|
30
32
|
"typescript": "^6.0.3",
|
|
31
33
|
"zod": "^4.3.6",
|
|
32
34
|
"zod-from-json-schema": "^0.5.2",
|
|
33
|
-
"a11y_parse": "^1.0.
|
|
35
|
+
"a11y_parse": "^1.0.8"
|
|
34
36
|
},
|
|
35
37
|
"devDependencies": {
|
|
36
38
|
"@types/express": "^4.17.21",
|
|
@@ -47,6 +49,8 @@
|
|
|
47
49
|
"inspect:playwright:chrome": "npx @modelcontextprotocol/inspector npx @playwright/mcp@latest --cdp-endpoint=chrome",
|
|
48
50
|
"inspect:playwright:cdp_endpoint": "npx @modelcontextprotocol/inspector npx @playwright/mcp@latest --cdp-endpoint=http://localhost:9222",
|
|
49
51
|
"inspect:playwright:extension": "npx @modelcontextprotocol/inspector npx @playwright/mcp@latest --extension",
|
|
52
|
+
"contribs:linkedin:profile": "npx tsx ./src/contribs/linkedin_cli/src/cli.ts profile jeromeetienne",
|
|
53
|
+
"contribs:twitter:profile": "npx tsx ./src/contribs/twitter_cli/src/cli.ts profile jerome_etienne",
|
|
50
54
|
"build": "tsc -p tsconfig.build.json",
|
|
51
55
|
"prepublish:check": "test -z \"$(git status --porcelain)\" || (echo 'Working tree dirty — commit or stash first' && exit 1)",
|
|
52
56
|
"version:bump": "npm version patch --no-git-tag-version && git add package.json && git commit -m \"feat: bump version in fastbrowser_cli package.json\"",
|
|
@@ -15,7 +15,7 @@ maps 1-to-1 to a FastBrowser tool and returns the tool's response on stdout.
|
|
|
15
15
|
Run the CLI directly via `tsx`:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
npx fastbrowser_cli <command> [flags]
|
|
18
|
+
npx fastbrowser_cli@latest <command> [flags]
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
## Typical Workflow
|
|
@@ -35,16 +35,41 @@ uid=1_0 RootWebArea "Example Domain" url="https://example.com/"
|
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
37
|
# List all open browser pages
|
|
38
|
-
npx fastbrowser_cli list_pages
|
|
38
|
+
npx fastbrowser_cli@latest list_pages
|
|
39
39
|
|
|
40
40
|
# Open a new page at a URL
|
|
41
|
-
npx fastbrowser_cli new_page --url https://example.com
|
|
41
|
+
npx fastbrowser_cli@latest new_page --url https://example.com
|
|
42
42
|
|
|
43
43
|
# Close a page by its numeric id
|
|
44
|
-
npx fastbrowser_cli close_page --page-id 1
|
|
44
|
+
npx fastbrowser_cli@latest close_page --page-id 1
|
|
45
45
|
|
|
46
46
|
# Navigate the current page to a URL
|
|
47
|
-
npx fastbrowser_cli navigate_page --url https://example.com
|
|
47
|
+
npx fastbrowser_cli@latest navigate_page --url https://example.com
|
|
48
|
+
|
|
49
|
+
# Restart the daemon - run this if pages opened by the bridge were closed manually
|
|
50
|
+
# and the MCP connection has broken
|
|
51
|
+
npx fastbrowser_cli@latest server restart
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
## Configuration
|
|
56
|
+
|
|
57
|
+
Global flags accepted by every command:
|
|
58
|
+
|
|
59
|
+
| Flag / env | Purpose | Default |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| `--server <url>` / `FASTBROWSER_SERVER` | URL of the `fastbrowser_httpd` daemon | `http://localhost:8787` |
|
|
62
|
+
| `--autostart` / `--no-autostart` | Auto-start the daemon if it is not already running | `--autostart` |
|
|
63
|
+
| `--mcp-target <target>` / `FASTBROWSER_MCP_TARGET` | Browser backend: `playwright` or `chrome_devtools` | `playwright` |
|
|
64
|
+
|
|
65
|
+
The daemon binds to one backend at startup. If it is already running with a different backend, the CLI refuses the request and prints the exact restart command to switch.
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Use chrome-devtools-mcp for one command
|
|
69
|
+
npx fastbrowser_cli@latest --mcp-target chrome_devtools list_pages
|
|
70
|
+
|
|
71
|
+
# Switch the running daemon to a different backend
|
|
72
|
+
npx fastbrowser_cli@latest --mcp-target chrome_devtools server restart
|
|
48
73
|
```
|
|
49
74
|
|
|
50
75
|
|
|
@@ -59,7 +84,7 @@ Matches nodes by their accessibility role.
|
|
|
59
84
|
```
|
|
60
85
|
button
|
|
61
86
|
link
|
|
62
|
-
|
|
87
|
+
combobox
|
|
63
88
|
searchbox
|
|
64
89
|
heading
|
|
65
90
|
WebArea
|
|
@@ -93,6 +118,7 @@ Attribute selectors match values inside `node.attributes`. The special virtual a
|
|
|
93
118
|
| `[attr^="prefix"]` | starts with |
|
|
94
119
|
| `[attr$="suffix"]` | ends with |
|
|
95
120
|
| `[attr*="sub"]` | contains substring |
|
|
121
|
+
| `[attr~="word"]` | contains `word` as a whole space-separated word |
|
|
96
122
|
|
|
97
123
|
```
|
|
98
124
|
link[href]
|
|
@@ -100,6 +126,7 @@ button[disabled="true"]
|
|
|
100
126
|
link[href^="https"]
|
|
101
127
|
link[href$=".com"]
|
|
102
128
|
link[href*="example"]
|
|
129
|
+
button[name~="Submit"]
|
|
103
130
|
heading[name="Welcome"]
|
|
104
131
|
link[name="Click \"here\""]
|
|
105
132
|
```
|
|
@@ -110,15 +137,56 @@ link[name="Click \"here\""]
|
|
|
110
137
|
|--------|-----------|
|
|
111
138
|
| `A B` | B is a descendant of A (any depth) |
|
|
112
139
|
| `A > B` | B is a direct child of A |
|
|
140
|
+
| `A + B` | B is the immediately following sibling of A |
|
|
141
|
+
| `A ~ B` | B is any following sibling of A |
|
|
113
142
|
| `A, B` | union — matches A or B |
|
|
114
143
|
|
|
115
144
|
```
|
|
116
145
|
WebArea link
|
|
117
146
|
main > button
|
|
147
|
+
label + textbox
|
|
148
|
+
link ~ link
|
|
118
149
|
heading, button
|
|
119
150
|
RootWebArea > link[href^="https"]
|
|
120
151
|
```
|
|
121
152
|
|
|
153
|
+
### Positional pseudo-classes
|
|
154
|
+
|
|
155
|
+
Narrow a match by position within the parent's children array. Indexing is 1-based; the root node never matches a positional pseudo-class.
|
|
156
|
+
|
|
157
|
+
| Syntax | Semantics |
|
|
158
|
+
|--------|-----------|
|
|
159
|
+
| `:first-child` | node is the first child of its parent |
|
|
160
|
+
| `:last-child` | node is the last child of its parent |
|
|
161
|
+
| `:nth-child(n)` | node is the nth child (1-based) |
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
link:first-child
|
|
165
|
+
button:last-child
|
|
166
|
+
menuitem:nth-child(2)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Functional pseudo-classes
|
|
170
|
+
|
|
171
|
+
Take a comma-separated selector list inside parentheses. The argument list itself supports the full selector language and may be nested.
|
|
172
|
+
|
|
173
|
+
| Syntax | Semantics |
|
|
174
|
+
|--------|-----------|
|
|
175
|
+
| `:is(s1, s2, …)` | node matches any selector in the list |
|
|
176
|
+
| `:where(s1, s2, …)` | alias of `:is()` (no specificity in this engine) |
|
|
177
|
+
| `:not(s1, s2, …)` | node matches none of the selectors |
|
|
178
|
+
| `:has(s1, s2, …)` | node has a descendant matching any selector |
|
|
179
|
+
|
|
180
|
+
`:has()` walks descendants of the candidate node (excluding the node itself). Relative leading combinators (e.g. `:has(> link)`) are not supported.
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
:is(heading, button)
|
|
184
|
+
link:not(:first-child)
|
|
185
|
+
*:has(button)
|
|
186
|
+
*:not(:has(link))
|
|
187
|
+
main > *:not(button)
|
|
188
|
+
```
|
|
189
|
+
|
|
122
190
|
### Examples
|
|
123
191
|
|
|
124
192
|
Sample accessibility tree:
|
|
@@ -136,58 +204,74 @@ uid=1 WebArea "Main Page"
|
|
|
136
204
|
|
|
137
205
|
Example queries on it:
|
|
138
206
|
- `link` matches all the links (uid=4, uid=7, uid=8)
|
|
139
|
-
-
|
|
207
|
+
- `navigation > link` matches only the links that are direct children of navigation (uid=7, uid=8)
|
|
140
208
|
- `link[href^="https"]` matches links with an external href (uid=4)
|
|
141
209
|
- `button[name="Submit"]` matches the submit button by name (uid=5)
|
|
142
210
|
- `*[disabled="true"]` matches any disabled element (uid=5)
|
|
143
211
|
- `heading, button` matches both headings and buttons in one query (uid=3, uid=5)
|
|
144
212
|
- `#7` matches a node by its UID (uid=7)
|
|
213
|
+
- `link:first-child` matches uid=4 and uid=7 (first child of `main` and `navigation`)
|
|
214
|
+
- `link + button` matches uid=5 (button immediately after a link)
|
|
215
|
+
- `:is(heading, button)` is equivalent to `heading, button` (uid=3, uid=5)
|
|
216
|
+
- `link:not([href^="https"])` matches the relative-href links (uid=7, uid=8)
|
|
217
|
+
- `*:has(button)` matches ancestors of a button (uid=1, uid=2)
|
|
145
218
|
|
|
146
219
|
## Inspection
|
|
147
220
|
|
|
148
221
|
- `query_selectors` is the most efficient way to get specific elements or data from the page. Use it instead of `take_snapshot` whenever possible.
|
|
149
222
|
- By default, `query_selectors` returns the first match per selector (cheaper, less output). Pass `-a, --all` when you need every match — pair it with `--limit` to cap results per selector.
|
|
223
|
+
- Use `--wa, --with-ancestors` to include each match's ancestor chain in the result, and `--wc, --with-children` to include the descendant subtree of each match.
|
|
150
224
|
|
|
151
225
|
```bash
|
|
152
226
|
# Query the accessibility tree returning the FIRST match per selector (--selector is repeatable)
|
|
153
|
-
npx fastbrowser_cli query_selectors --selector "button" --selector "link"
|
|
227
|
+
npx fastbrowser_cli@latest query_selectors --selector "button" --selector "link"
|
|
154
228
|
|
|
155
|
-
#
|
|
156
|
-
npx fastbrowser_cli query_selectors --selector 'heading[level="1"]' --
|
|
229
|
+
# Include ancestor nodes in the result
|
|
230
|
+
npx fastbrowser_cli@latest query_selectors --selector 'heading[level="1"]' --with-ancestors
|
|
157
231
|
|
|
158
|
-
#
|
|
159
|
-
npx fastbrowser_cli query_selectors
|
|
160
|
-
|
|
232
|
+
# Include the descendant subtree of each match
|
|
233
|
+
npx fastbrowser_cli@latest query_selectors --selector 'main' --with-children
|
|
234
|
+
|
|
235
|
+
# Per-selector control over withAncestors / withChildren via JSON
|
|
236
|
+
npx fastbrowser_cli@latest query_selectors \
|
|
237
|
+
--selectors-json '[{"selector":"button","withAncestors":true},{"selector":"link","withChildren":true}]'
|
|
161
238
|
|
|
162
239
|
# Pass --all to return every match per selector; --limit caps results per selector (0 = unlimited)
|
|
163
|
-
npx fastbrowser_cli query_selectors --all --selector "button" --selector "link" --limit 5
|
|
240
|
+
npx fastbrowser_cli@latest query_selectors --all --selector "button" --selector "link" --limit 5
|
|
164
241
|
|
|
165
|
-
#
|
|
166
|
-
npx fastbrowser_cli query_selectors --all --selector 'heading[level="1"]' --
|
|
242
|
+
# Include ancestor nodes in the result
|
|
243
|
+
npx fastbrowser_cli@latest query_selectors --all --selector 'heading[level="1"]' --with-ancestors
|
|
167
244
|
|
|
168
|
-
# Per-selector control over limit / withAncestors via JSON (with --all)
|
|
169
|
-
npx fastbrowser_cli query_selectors --all \
|
|
170
|
-
--selectors-json '[{"selector":"button","limit":3,"withAncestors":true},{"selector":"link","limit":0,"
|
|
245
|
+
# Per-selector control over limit / withAncestors / withChildren via JSON (with --all)
|
|
246
|
+
npx fastbrowser_cli@latest query_selectors --all \
|
|
247
|
+
--selectors-json '[{"selector":"button","limit":3,"withAncestors":true},{"selector":"link","limit":0,"withChildren":true}]'
|
|
171
248
|
|
|
172
249
|
# Take an accessibility-tree full page snapshot of the current page - very expensive, prefer targeted queries when possible
|
|
173
|
-
npx fastbrowser_cli take_snapshot
|
|
250
|
+
npx fastbrowser_cli@latest take_snapshot
|
|
174
251
|
```
|
|
175
252
|
|
|
176
253
|
## Interaction
|
|
177
254
|
|
|
178
255
|
```bash
|
|
179
256
|
# Click by a direct uid reference (fast path - no accessibility-tree lookup)
|
|
180
|
-
npx fastbrowser_cli click --selector "#1_42"
|
|
257
|
+
npx fastbrowser_cli@latest click --selector "#1_42"
|
|
181
258
|
|
|
182
259
|
# Click by any CSS-like selector - resolved to a uid internally
|
|
183
|
-
npx fastbrowser_cli click -s 'button[name="Submit"]'
|
|
260
|
+
npx fastbrowser_cli@latest click -s 'button[name="Submit"]'
|
|
184
261
|
|
|
185
262
|
# Fill a single form field - selector can be a uid (#1_7) or any CSS-like selector
|
|
186
|
-
npx fastbrowser_cli fill_form -s 'textbox[name="Email"]' -v "hello@example.com"
|
|
263
|
+
npx fastbrowser_cli@latest fill_form -s 'textbox[name="Email"]' -v "hello@example.com"
|
|
187
264
|
|
|
188
265
|
# Press a comma-separated sequence of keys (literals and named keys both work)
|
|
189
|
-
npx fastbrowser_cli press_keys --keys "Tab, Tab, Enter"
|
|
190
|
-
npx fastbrowser_cli press_keys --keys "Hello, Tab, Enter"
|
|
266
|
+
npx fastbrowser_cli@latest press_keys --keys "Tab, Tab, Enter"
|
|
267
|
+
npx fastbrowser_cli@latest press_keys --keys "Hello, Tab, Enter"
|
|
268
|
+
|
|
269
|
+
# Evaluate a JS function in the page context and get its JSON-able return value
|
|
270
|
+
npx fastbrowser_cli@latest evaluate_script --script 'function() { return { title: document.title, url: location.href }; }'
|
|
271
|
+
|
|
272
|
+
# Same, reading the function from a file or piped stdin
|
|
273
|
+
npx fastbrowser_cli@latest evaluate_script ./my_script.js
|
|
274
|
+
echo 'function() { return document.querySelectorAll("a").length; }' | npx fastbrowser_cli@latest evaluate_script
|
|
191
275
|
```
|
|
192
276
|
|
|
193
277
|
## Batch Execution
|
|
@@ -204,16 +288,16 @@ By default, the batch stops at the first failing line (shell `set -e` semantics)
|
|
|
204
288
|
|
|
205
289
|
```bash
|
|
206
290
|
# From a file
|
|
207
|
-
npx fastbrowser_cli batch ./demo.fbs
|
|
291
|
+
npx fastbrowser_cli@latest batch ./demo.fbs
|
|
208
292
|
|
|
209
293
|
# Piped on stdin
|
|
210
|
-
cat demo.fbs | npx fastbrowser_cli batch
|
|
294
|
+
cat demo.fbs | npx fastbrowser_cli@latest batch
|
|
211
295
|
|
|
212
296
|
# Inline script
|
|
213
|
-
npx fastbrowser_cli batch --script $'press_keys --keys "Enter"\nclick -s \'button[name^="Tout effacer"]\''
|
|
297
|
+
npx fastbrowser_cli@latest batch --script $'press_keys --keys "Enter"\nclick -s \'button[name^="Tout effacer"]\''
|
|
214
298
|
|
|
215
299
|
# Continue through failures
|
|
216
|
-
npx fastbrowser_cli batch --no-stop-on-error ./demo.fbs
|
|
300
|
+
npx fastbrowser_cli@latest batch --no-stop-on-error ./demo.fbs
|
|
217
301
|
```
|
|
218
302
|
|
|
219
303
|
Example `demo.fbs`:
|
|
@@ -238,10 +322,13 @@ press_keys --keys "Tab, Enter"
|
|
|
238
322
|
| `click` | Click an element by accessibility selector | `--selector` / `-s` |
|
|
239
323
|
| `fill_form` | Fill a form field by accessibility selector | `--selector` / `-s`, `--value` |
|
|
240
324
|
| `press_keys` | Press a comma-separated key sequence | `--keys` |
|
|
325
|
+
| `evaluate_script` | Run a JS function in the page context and return its JSON-able result | one of: `<file>`, `--script`, or piped stdin |
|
|
241
326
|
| `batch` | Run multiple commands from a file, piped stdin, or `--script` inline | one of: `<file>`, `--script`, or piped stdin |
|
|
327
|
+
| `install [skill-folder]` | Install bundled skills into `<skill-folder>/skills/` (default: `.`) | — |
|
|
242
328
|
| `server start` | Start the HTTP server daemon | — |
|
|
243
329
|
| `server status` | Report server running/stopped | — |
|
|
244
330
|
| `server stop` | Stop the HTTP server | — |
|
|
331
|
+
| `server restart` | Restart the HTTP server (re-establishes the MCP connection) | — |
|
|
245
332
|
|
|
246
333
|
## Output & Errors
|
|
247
334
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
|
|
3
|
+
const __dirname = new URL('.', import.meta.url).pathname;
|
|
4
|
+
|
|
5
|
+
export class FastBrowserHelper {
|
|
6
|
+
static async run(command: string): Promise<string> {
|
|
7
|
+
// const fullCommand = `npx fastbrowser_cli ${command}`;
|
|
8
|
+
const fullCommand = `npx tsx ${__dirname}../../fastbrowser_cli/fastbrowser_cli.ts ${command}`;
|
|
9
|
+
console.error(`Running command: ${fullCommand}`);
|
|
10
|
+
return execSync(fullCommand, { encoding: 'utf8' });
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static async navigatePage(url: string): Promise<void> {
|
|
14
|
+
await FastBrowserHelper.run(`navigate_page --url '${url}'`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static async fillForm(selector: string, value: string): Promise<void> {
|
|
18
|
+
await FastBrowserHelper.run(`fill_form --selector '${selector}' --value '${value}'`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static async pressKeys(keys: string): Promise<void> {
|
|
22
|
+
await FastBrowserHelper.run(`press_keys --keys '${keys}'`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static async click(selector: string): Promise<void> {
|
|
26
|
+
await FastBrowserHelper.run(`click -s '${selector}'`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static async querySelectorsAll(selector: string, limit: number): Promise<string> {
|
|
30
|
+
return await FastBrowserHelper.run(`query_selectors --all --selector '${selector}' --limit ${limit}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static async querySelectorsAllWithChildren(selector: string, limit: number): Promise<string> {
|
|
34
|
+
return await FastBrowserHelper.run(`query_selectors --all --selector '${selector}' --limit ${limit} --with-ancestors --with-children`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static async takeSnapshot(): Promise<string> {
|
|
38
|
+
return await FastBrowserHelper.run('take_snapshot');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static async querySelectors(selector: string, withAncestors = true): Promise<string> {
|
|
42
|
+
const flag = withAncestors === false ? ' --no-with-ancestors' : '';
|
|
43
|
+
return await FastBrowserHelper.run(`query_selectors --selector '${selector}'${flag}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static async evaluateScript(functionText: string): Promise<string> {
|
|
47
|
+
return await FastBrowserHelper.run(`evaluate_script --script "${functionText}"`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# linkedin_cli
|
|
2
|
+
|
|
3
|
+
Command-line tool to interact with LinkedIn through a real browser session, driven by `fastbrowser_cli`.
|
|
4
|
+
|
|
5
|
+
It lets you create posts on the feed and manage direct-message conversations (list, read, send) from the terminal.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- A running `fastbrowser_cli` session already authenticated on `linkedin.com`.
|
|
10
|
+
- The `_shared/fastbrowser_helper.ts` wrapper located in the sibling `contribs/_shared/` folder.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx tsx ./src/cli.ts <command> [args]
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Commands
|
|
19
|
+
|
|
20
|
+
| Command | Description |
|
|
21
|
+
|---------|-------------|
|
|
22
|
+
| `post <content>` | Create a post on the LinkedIn feed. |
|
|
23
|
+
| `dm_page` | Navigate to the LinkedIn messaging page. Run this first before any `dm_*` command. |
|
|
24
|
+
| `dm_list` | List the names of people you have conversations with. |
|
|
25
|
+
| `dm_send <target_user> <message>` | Send a message in an existing conversation with `target_user`. |
|
|
26
|
+
| `dm_thread <target_user>` | Print the message thread of a conversation with `target_user`. |
|
|
27
|
+
| `profile <slug>` | Export a LinkedIn profile by slug (the path component of `/in/<slug>/`). Use `-f json` for JSON output. |
|
|
28
|
+
|
|
29
|
+
`target_user` is matched against the conversation heading via a prefix match (e.g. `"Jerome"` matches `"Jerome Etienne"`).
|
|
30
|
+
|
|
31
|
+
### Examples
|
|
32
|
+
|
|
33
|
+
Create a post:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx tsx ./src/cli.ts post "Hello LinkedIn from the CLI"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
List your conversations:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npx tsx ./src/cli.ts dm_page
|
|
43
|
+
npx tsx ./src/cli.ts dm_list
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Read a thread:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npx tsx ./src/cli.ts dm_thread "Jerome Etienne"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Output is one message per line in the form:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
2026-05-03T14:32:00:Jerome Etienne: hey, are you free this week?
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Send a reply:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npx tsx ./src/cli.ts dm_send "Jerome Etienne" "Sure, Thursday afternoon works."
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Export a profile as markdown (default):
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npx tsx ./src/cli.ts profile jeromeetienne
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Export the same profile as JSON:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npx tsx ./src/cli.ts profile jeromeetienne -f json
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Layout
|
|
77
|
+
|
|
78
|
+
- [src/cli.ts](src/cli.ts) — Commander entry point, defines the commands and orchestrates browser actions through `FastBrowserHelper`.
|
|
79
|
+
- [src/libs/linkedin_thread_helper.ts](src/libs/linkedin_thread_helper.ts) — Parses the LinkedIn message thread from an accessibility tree snapshot into timestamped lines.
|
|
80
|
+
- [src/libs/linkedin_profile_helper.ts](src/libs/linkedin_profile_helper.ts) — Parses a LinkedIn profile snapshot into a typed `LinkedinProfile` (header, About, Experience, Education) with markdown rendering.
|