semrush-cli 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +174 -158
- package/assets/demo-keywords.gif +0 -0
- package/assets/demo-keywords.png +0 -0
- package/assets/demo-projects.gif +0 -0
- package/assets/demo-projects.png +0 -0
- package/assets/logo-lockup.svg +10 -0
- package/assets/logo.png +0 -0
- package/assets/logo.svg +4 -8
- package/dist/{auth-BZhlPkLq.js → auth-CrYOA8QT.js} +4 -4
- package/dist/{auth-BZhlPkLq.js.map → auth-CrYOA8QT.js.map} +1 -1
- package/dist/{browser-layer-BJ4eQAUz.js → browser-layer-gdm03TCV.js} +25 -12
- package/dist/browser-layer-gdm03TCV.js.map +1 -0
- package/dist/cli.js +24 -24
- package/dist/cli.js.map +1 -1
- package/dist/{errors-CU9T4acd.js → errors-DNn_XeoU.js} +517 -4
- package/dist/errors-DNn_XeoU.js.map +1 -0
- package/dist/{mcp-BKmnk8Wq.js → mcp-DqvGEnxx.js} +6 -6
- package/dist/{mcp-BKmnk8Wq.js.map → mcp-DqvGEnxx.js.map} +1 -1
- package/dist/{session-layer-BDgTji_P.js → session-layer-Bq5OpnR5.js} +8 -7
- package/dist/{session-layer-BDgTji_P.js.map → session-layer-Bq5OpnR5.js.map} +1 -1
- package/dist/{validation-Qgx4O9Cz.js → validation-B3hdOxdH.js} +4 -4
- package/dist/validation-B3hdOxdH.js.map +1 -0
- package/dist/validation-B8xjCr9w.js +4 -0
- package/package.json +2 -2
- package/dist/browser-layer-BJ4eQAUz.js.map +0 -1
- package/dist/errors-CU9T4acd.js.map +0 -1
- package/dist/validation-D0km8JI3.js +0 -4
- package/dist/validation-Qgx4O9Cz.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,221 +1,237 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="assets/logo.svg" width="
|
|
2
|
+
<img src="assets/logo-lockup.svg" width="720" alt="semrush cli logo">
|
|
3
3
|
</p>
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
<p align="center">
|
|
6
|
-
<a href="https://github.com/Microck/semrush-cli/
|
|
7
|
-
<a href="https://www.npmjs.com/package/semrush-cli"><img src="https://img.shields.io/npm/
|
|
8
|
-
<a href="https://github.com/Microck/semrush-cli/
|
|
9
|
-
<a href="LICENSE"><img src="https://img.shields.io/
|
|
6
|
+
<a href="https://github.com/Microck/semrush-cli/releases"><img src="https://img.shields.io/github/v/release/Microck/semrush-cli?display_name=tag&style=flat-square&label=release&color=000000" alt="release badge"></a>
|
|
7
|
+
<a href="https://www.npmjs.com/package/semrush-cli"><img src="https://img.shields.io/npm/dt/semrush-cli?style=flat-square&label=downloads&color=000000" alt="npm downloads"></a>
|
|
8
|
+
<a href="https://github.com/Microck/semrush-cli/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/Microck/semrush-cli/ci.yml?branch=main&style=flat-square&label=ci&color=000000" alt="ci badge"></a>
|
|
9
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-mit-000000?style=flat-square" alt="license badge"></a>
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
-
semrush
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
`semrush` is a terminal cli for semrush. research keywords, check rankings and backlinks, compare competitors, manage projects and keyword lists, and run site audits from your own account. output is json, so you can pipe it into `jq` or give the same commands to an agent through mcp. built with typescript and effect.
|
|
15
|
+
|
|
16
|
+
[documentation](https://semrush.micr.dev) | [command reference](https://semrush.micr.dev/docs/reports) | [npm](https://www.npmjs.com/package/semrush-cli) | [mcp](https://semrush.micr.dev/docs/mcp)
|
|
17
17
|
|
|
18
|
-
[
|
|
18
|
+

|
|
19
19
|
|
|
20
20
|
## why
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
scripts, account totals and pagination, project management, and encrypted session storage.
|
|
24
|
-
no Semrush developer API key or Python runtime required.
|
|
22
|
+
if you already pay for semrush, you should be able to use it from the terminal too. this cli uses your existing web session, so there is no developer api key to buy or configure. look up a keyword, save the result, compare a few domains, or let an agent do it through mcp.
|
|
25
23
|
|
|
26
|
-
|
|
24
|
+
your plan's permissions and limits still apply. it doesn't cover the whole semrush suite. the [coverage page](https://semrush.micr.dev/docs/coverage) lists what works and what still needs the web ui.
|
|
27
25
|
|
|
28
26
|
## quickstart
|
|
29
27
|
|
|
30
|
-
|
|
31
|
-
macOS x64/arm64 and Windows x64.
|
|
28
|
+
### install
|
|
32
29
|
|
|
33
|
-
|
|
30
|
+
requires node.js 22 or newer. linux, macos and windows are supported.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
34
33
|
npm install -g semrush-cli
|
|
35
|
-
semrush
|
|
36
|
-
semrush
|
|
37
|
-
semrush
|
|
34
|
+
semrush setup
|
|
35
|
+
semrush auth login
|
|
36
|
+
semrush keyword-overview --keyword 'email marketing'
|
|
38
37
|
```
|
|
39
38
|
|
|
40
|
-
`
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
libraries can be installed with `npx patchright install-deps chromium`.
|
|
39
|
+
`semrush-cli` is the npm package. `semrush` is the command.
|
|
40
|
+
|
|
41
|
+
`setup` downloads chromium and starts the bundled galleton session engine. there is no separate python or go install. on linux, if chromium needs system libraries, run `npx patchright install-deps chromium`.
|
|
44
42
|
|
|
45
|
-
|
|
43
|
+
### auth
|
|
46
44
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
`semrush auth login` opens a browser. sign in to semrush there and the cli saves the session in galleton's encrypted vault. it doesn't ask for your password in the terminal.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
semrush auth login
|
|
49
|
+
semrush auth status --check --json
|
|
50
|
+
semrush doctor
|
|
50
51
|
```
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
already have a signed-in browser with a local debugging port? import its session instead:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
semrush auth import --cdp-url http://127.0.0.1:9234
|
|
57
|
+
semrush doctor
|
|
58
|
+
```
|
|
56
59
|
|
|
57
|
-
|
|
60
|
+
the browser has to be running with debugging enabled. import doesn't start or stop it. see the [authentication guide](https://semrush.micr.dev/docs/authentication) for headless hosts and remote browsers.
|
|
58
61
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
semrush
|
|
63
|
-
semrush
|
|
64
|
-
semrush
|
|
65
|
-
semrush-cli project-set-tags --folder-id 123 --tags '["client"]' --confirm
|
|
66
|
-
semrush-cli project-pin --folder-id 123 --pinned --confirm
|
|
67
|
-
semrush-cli project-delete --folder-id 123 --confirm
|
|
62
|
+
semrush can expire your session. sign in or import again when that happens. the cli saves rotated cookies after successful requests, but doesn't renew expired sessions in the background.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
semrush auth logout
|
|
66
|
+
semrush daemon stop
|
|
67
|
+
semrush daemon start
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
automatic Site Audit/Position Tracking setup are separate, explicit commands.
|
|
74
|
-
See [projects](https://semrush.micr.dev/docs/projects) and
|
|
75
|
-
[web UI coverage](https://semrush.micr.dev/docs/coverage).
|
|
70
|
+
logout forgets this cli's saved session. it doesn't log out your other browsers. the daemon keeps running after the terminal closes. start it again after a reboot.
|
|
71
|
+
|
|
72
|
+
## command surface
|
|
76
73
|
|
|
77
|
-
|
|
74
|
+
89 operations, available as cli commands and mcp tools.
|
|
78
75
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
76
|
+
| command | what it does |
|
|
77
|
+
| --- | --- |
|
|
78
|
+
| `keyword-overview`, `keyword-magic` | volume, difficulty, cpc, intent, related keywords and filtered research |
|
|
79
|
+
| `keyword-serp`, `keyword-ads`, `keyword-clusters` | search results, ads and keyword clusters |
|
|
80
|
+
| `domain-overview`, `domain-keywords`, `domain-competitors` | organic rankings and competing domains |
|
|
81
|
+
| `domain-pages`, `domain-subdomains`, `domain-position-changes` | pages, subdomains and ranking changes |
|
|
82
|
+
| `keyword-gap`, `backlink-gap` | compare domains and find keyword or backlink opportunities |
|
|
83
|
+
| `backlink-links`, `backlink-referring-domains`, `backlink-anchors` | inspect backlinks, referring domains and anchor text |
|
|
84
|
+
| `domain-ai-visibility`, `domain-ai-countries`, `domain-ai-sources` | ai visibility, countries and citation sources |
|
|
85
|
+
| `project-create`, `project-get`, `project-update`, `project-delete` | create and manage projects |
|
|
86
|
+
| `project-tags`, `project-set-tags`, `project-pin` | organize your projects |
|
|
87
|
+
| `project-enable-seo`, `project-tools`, `project-toolkits` | enable seo and read project tool status |
|
|
88
|
+
| `keyword-lists`, `keyword-list-create`, `keyword-list-import` | manage keyword lists and import keywords |
|
|
89
|
+
| `keyword-strategy-create`, `keyword-list-cluster` | generate a strategy or cluster a list |
|
|
90
|
+
| `audit-create`, `audit-configure`, `audit-start` | configure and launch a site audit |
|
|
91
|
+
| `audit-status`, `audit-snapshots`, `audit-snapshot` | check progress and read audit results |
|
|
92
|
+
| `reports` | list every operation and its inputs |
|
|
93
|
+
| `mcp` | run the stdio mcp server |
|
|
94
|
+
| `doctor` | check the browser, session engine and semrush connection |
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
semrush reports
|
|
98
|
+
semrush keyword-magic --help
|
|
99
|
+
semrush project-create --help
|
|
86
100
|
```
|
|
87
101
|
|
|
88
|
-
|
|
89
|
-
and structured strategy generation are separate commands. Metric refresh and
|
|
90
|
-
clustering require explicit confirmation and consume account allowances.
|
|
91
|
-
See [keyword lists](https://semrush.micr.dev/docs/keyword-lists).
|
|
102
|
+
global flags: `--json`, `--no-color`, `--no-input`. reports return json with or without `--json`. objects and arrays use json arguments. use `--help` on a command for its filters, pagination and defaults.
|
|
92
103
|
|
|
93
|
-
##
|
|
104
|
+
## examples
|
|
94
105
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
semrush
|
|
99
|
-
semrush
|
|
100
|
-
semrush
|
|
101
|
-
semrush-cli backlink-gap --domains '["openai.com","anthropic.com"]' --json
|
|
102
|
-
semrush-cli backlink-links --domain openai.com --filters '+|type||nofollow' --json
|
|
103
|
-
semrush-cli domain-ai-visibility --domain openai.com --json
|
|
104
|
-
semrush-cli snapshot-dates --database us --json
|
|
105
|
-
semrush-cli reports --json
|
|
106
|
-
semrush-cli domain-keywords --help
|
|
106
|
+
### keyword research
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
semrush keyword-overview --keyword 'email marketing'
|
|
110
|
+
semrush keyword-magic --keyword 'email marketing' --questions-only --page-size 20
|
|
111
|
+
semrush keyword-serp --keyword 'email marketing'
|
|
107
112
|
```
|
|
108
113
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
114
|
+
pull out the numbers you care about:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
semrush keyword-overview --keyword 'email marketing' \
|
|
118
|
+
| jq '.data | {phrase, volume, difficulty, cpc}'
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### competitors and backlinks
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
semrush domain-overview --domain openai.com
|
|
125
|
+
semrush domain-keywords --domain openai.com --page-size 20
|
|
126
|
+
semrush keyword-gap --domains '["openai.com","anthropic.com"]'
|
|
127
|
+
semrush backlink-links --domain openai.com
|
|
128
|
+
semrush backlink-gap --domains '["openai.com","anthropic.com"]'
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### projects
|
|
132
|
+
|
|
133
|
+
preview a write before sending it:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
semrush project-create --name 'my website' --domain example.com --dry-run
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
then create it when you're ready:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
semrush project-create --name 'my website' --domain example.com --confirm
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+

|
|
146
|
+
|
|
147
|
+
writes need `--confirm`. `--dry-run` validates the inputs and prints the request without connecting to semrush. creating a project doesn't start tools or share it.
|
|
148
|
+
|
|
149
|
+
### keyword lists
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
semrush keyword-lists
|
|
153
|
+
semrush keyword-list-create --name 'content ideas' --confirm
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
use the list id and owner id returned by semrush:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
semrush keyword-list-import --basket-id 123 --owner-id 456 \
|
|
160
|
+
--keywords '["email marketing","email automation"]' --database us --confirm
|
|
161
|
+
semrush keyword-list-keywords --basket-id 123 --owner-id 456
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
strategy generation, clustering and metric updates can consume your account allowance. they need explicit confirmation too. see [keyword lists](https://semrush.micr.dev/docs/keyword-lists).
|
|
165
|
+
|
|
166
|
+
### site audits
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
semrush project-enable-seo --folder-id 123 --confirm
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
use the returned seo project `id` as the campaign id:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
semrush audit-create --campaign-id 456 --name 'my audit' \
|
|
176
|
+
--domain example.com --page-limit 100 --confirm
|
|
177
|
+
semrush audit-start --campaign-id 456 --confirm
|
|
178
|
+
semrush audit-status --campaign-id 456
|
|
179
|
+
semrush audit-snapshots --campaign-id 456
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
creating an audit saves its settings. starting it is a separate command. defaults are manual scheduling and email off. see [site audit](https://semrush.micr.dev/docs/site-audit) for crawl settings and limits.
|
|
125
183
|
|
|
126
184
|
## mcp
|
|
127
185
|
|
|
128
|
-
|
|
186
|
+
finish setup and sign in first, then add this to your client's mcp config:
|
|
129
187
|
|
|
130
188
|
```json
|
|
131
189
|
{
|
|
132
190
|
"mcpServers": {
|
|
133
191
|
"semrush": {
|
|
134
|
-
"command": "semrush
|
|
192
|
+
"command": "semrush",
|
|
135
193
|
"args": ["mcp"]
|
|
136
194
|
}
|
|
137
195
|
}
|
|
138
196
|
}
|
|
139
197
|
```
|
|
140
198
|
|
|
141
|
-
|
|
142
|
-
PATH. `npx -y semrush-cli@0.3.0 mcp` also works. MCP tool names use underscores,
|
|
143
|
-
for example `keyword_overview` and `domain_keywords`. Input schemas and reports
|
|
144
|
-
match the CLI. The 62 read tools carry read-only annotations. The 19 write tools require
|
|
145
|
-
`confirm:true`, or accept `dry_run:true` to preview the request. Delete and leave
|
|
146
|
-
also carry destructive annotations. Login, arbitrary URLs and JavaScript
|
|
147
|
-
execution are not MCP tools.
|
|
148
|
-
|
|
149
|
-
## sessions
|
|
150
|
-
|
|
151
|
-
```sh
|
|
152
|
-
semrush-cli auth status --check --json
|
|
153
|
-
semrush-cli auth logout
|
|
154
|
-
semrush-cli daemon stop
|
|
155
|
-
semrush-cli daemon start
|
|
156
|
-
```
|
|
199
|
+
the server exposes the same operations as the cli. tool names use underscores, such as `keyword_overview` and `project_create`. writes need `confirm: true`, or `dry_run: true` to preview the request. it doesn't expose login, arbitrary urls or javascript execution.
|
|
157
200
|
|
|
158
|
-
|
|
159
|
-
private daemon listens on `127.0.0.1:8768`. It continues after the terminal closes;
|
|
160
|
-
run `daemon start` after reboot. The CLI installs no system startup service.
|
|
201
|
+
## what it looks like
|
|
161
202
|
|
|
162
|
-
|
|
163
|
-
context. The MCP server reuses one context and serializes requests. Successful
|
|
164
|
-
reports capture cookie updates back to Galleton. Session expiry requires sign-in
|
|
165
|
-
or import again. No anonymous fallback or automatic request retries.
|
|
203
|
+
the gifs use captured output for public keyword research and an offline project preview. no account details or credentials. the [capture notes and renderer](docs/demo/README.md) are in the repo if you want to regenerate them.
|
|
166
204
|
|
|
167
|
-
|
|
168
|
-
because it is not on npm. The bundled daemon adds a tested `static` provider for
|
|
169
|
-
storage without renewal. Semrush has no proven renewal contract in the reference
|
|
170
|
-
integration, so this tool does not invent one. See [architecture](docs/architecture.md)
|
|
171
|
-
and [SDK provenance](src/vendor/README.md).
|
|
205
|
+
## building from source
|
|
172
206
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
daemon must support the documented static-provider extension. Never expose its
|
|
182
|
-
API token or credential directory.
|
|
207
|
+
```bash
|
|
208
|
+
git clone https://github.com/Microck/semrush-cli.git
|
|
209
|
+
cd semrush-cli
|
|
210
|
+
npm ci
|
|
211
|
+
npm run build
|
|
212
|
+
node dist/cli.js --help
|
|
213
|
+
npm run check
|
|
214
|
+
```
|
|
183
215
|
|
|
184
|
-
|
|
216
|
+
the source build uses go to build the pinned galleton engine. npm releases include the engine for supported platforms.
|
|
185
217
|
|
|
186
|
-
|
|
187
|
-
can consume an allowance. Internal web endpoints may change. Provider caps remain
|
|
188
|
-
visible; there is no unlimited-export claim. Galleton encrypts at rest but its key
|
|
189
|
-
and vault share a private local directory. Other processes running as your OS user
|
|
190
|
-
are within the same trust boundary.
|
|
218
|
+
## documentation
|
|
191
219
|
|
|
192
|
-
|
|
220
|
+
full docs live at [semrush.micr.dev](https://semrush.micr.dev). setup, authentication, projects, keyword lists, site audits, mcp and the complete command reference.
|
|
193
221
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
npm --prefix docs-site run build
|
|
199
|
-
```
|
|
222
|
+
- [coverage](https://semrush.micr.dev/docs/coverage)
|
|
223
|
+
- [authentication](https://semrush.micr.dev/docs/authentication)
|
|
224
|
+
- [scripting](https://semrush.micr.dev/docs/scripting)
|
|
225
|
+
- [architecture](docs/architecture.md)
|
|
200
226
|
|
|
201
|
-
|
|
202
|
-
daemon with its storage-only extension. The build runs the upstream core suite
|
|
203
|
-
with the extension's integration test. Published users do not need Go.
|
|
227
|
+
## contributing
|
|
204
228
|
|
|
205
|
-
|
|
206
|
-
Chromium and Galleton with a local HTTP fixture, and exercise the built executable.
|
|
207
|
-
They never require a Semrush account. See [verification](docs/verification.md) for
|
|
208
|
-
the separate live-account evidence.
|
|
229
|
+
issues and pull requests are welcome. if semrush changes an endpoint, include the command you ran and the error. leave cookies and account details out of the report.
|
|
209
230
|
|
|
210
|
-
##
|
|
231
|
+
## disclaimer
|
|
211
232
|
|
|
212
|
-
|
|
213
|
-
semrush-cli auth logout
|
|
214
|
-
semrush-cli daemon stop
|
|
215
|
-
npm uninstall -g semrush-cli
|
|
216
|
-
```
|
|
233
|
+
this is an unofficial client, not affiliated with semrush. it uses the web product's internal endpoints, which can change. your subscription and account limits apply.
|
|
217
234
|
|
|
218
|
-
|
|
219
|
-
checking they contain nothing you need.
|
|
235
|
+
## license
|
|
220
236
|
|
|
221
|
-
|
|
237
|
+
[mit license](LICENSE)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 230" role="img" aria-labelledby="title">
|
|
2
|
+
<title id="title">semrush cli</title>
|
|
3
|
+
<style>.wordmark{fill:#421983}@media(prefers-color-scheme:dark){.wordmark{fill:#fff}}</style>
|
|
4
|
+
<g transform="translate(12 38) scale(.48)"> <path d="M357.481 3C333.269 3 306.873 11.7835 277.382 27.1205L113.044 114.41H247.71L3 244.524H272.376L136.164 316.977H361.44C446.818 314.792 515.038 245.48 515.038 160.011C515.038 74.5425 444.178 3.04552 357.481 3.04552V3Z" fill="#ff642d"/>
|
|
5
|
+
<path d="M136.164 316.977L272.376 244.524H408L272 316.977Z" fill="#a76bff"/>
|
|
6
|
+
<path d="m317 116 47 44-47 44m73 0h52" fill="none" stroke="#421983" stroke-width="22" stroke-linecap="square" stroke-linejoin="miter"/>
|
|
7
|
+
</g>
|
|
8
|
+
<g class="wordmark" transform="translate(287 153) scale(0.13079394217530976 -0.13079394217530976)"><path d="M283 -12Q218 -12 163.0 12.5Q108 37 72.5 82.0Q37 127 30 188H149Q154 157 175.0 133.0Q196 109 225.5 96.0Q255 83 287 83Q331 83 358.5 103.0Q386 123 386 155Q386 186 367.5 203.0Q349 220 319.0 229.5Q289 239 253.5 246.0Q218 253 182.0 262.5Q146 272 116.0 289.5Q86 307 67.5 337.5Q49 368 49 417Q49 468 76.0 506.5Q103 545 152.0 566.5Q201 588 266 588Q326 588 377.5 565.5Q429 543 463.0 502.5Q497 462 504 408H383Q373 445 340.0 469.5Q307 494 261 494Q219 494 194.0 476.0Q169 458 169 429Q169 402 187.5 387.5Q206 373 236.0 364.5Q266 356 302.0 349.0Q338 342 374.0 331.5Q410 321 440.0 302.0Q470 283 488.5 250.5Q507 218 507 166Q507 114 478.0 73.5Q449 33 398.5 10.5Q348 -12 283 -12Z M867 -12Q783 -12 719.5 28.0Q656 68 621.0 136.0Q586 204 586 288Q586 373 620.0 440.5Q654 508 714.5 548.0Q775 588 856 588Q941 588 1002.0 547.5Q1063 507 1091.5 436.5Q1120 366 1107 276H705Q707 225 726.5 184.0Q746 143 782.0 119.5Q818 96 867 96Q920 96 954.5 121.5Q989 147 1000 188H1122Q1105 94 1035.0 41.0Q965 -12 867 -12ZM712 365H990Q986 418 950.5 451.5Q915 485 860 485Q807 485 767.0 453.5Q727 422 712 365Z M1945 0V350Q1945 409 1914.5 444.0Q1884 479 1831 479Q1774 479 1741.0 435.0Q1708 391 1708 327V0H1587V350Q1587 409 1556.5 444.0Q1526 479 1473 479Q1416 479 1383.5 435.0Q1351 391 1351 327V0H1229V576H1335L1345 482Q1370 533 1412.0 560.5Q1454 588 1508 588Q1571 588 1618.5 558.5Q1666 529 1689 476Q1719 533 1764.5 560.5Q1810 588 1866 588Q1955 588 2010.5 531.0Q2066 474 2066 375V0Z M2204 0V576H2310L2319 484Q2332 526 2363.5 551.0Q2395 576 2438 576H2529L2543 470H2446Q2385 470 2355.5 424.5Q2326 379 2326 302V0Z M2826 -12Q2765 -12 2718.0 14.0Q2671 40 2645.0 88.0Q2619 136 2619 201V576H2740V226Q2740 167 2773.0 132.5Q2806 98 2861 98Q2921 98 2955.0 141.5Q2989 185 2989 249V576H3110V0H3005L2995 95Q2969 44 2925.5 16.0Q2882 -12 2826 -12Z M3465 -12Q3400 -12 3345.0 12.5Q3290 37 3254.5 82.0Q3219 127 3212 188H3331Q3336 157 3357.0 133.0Q3378 109 3407.5 96.0Q3437 83 3469 83Q3513 83 3540.5 103.0Q3568 123 3568 155Q3568 186 3549.5 203.0Q3531 220 3501.0 229.5Q3471 239 3435.5 246.0Q3400 253 3364.0 262.5Q3328 272 3298.0 289.5Q3268 307 3249.5 337.5Q3231 368 3231 417Q3231 468 3258.0 506.5Q3285 545 3334.0 566.5Q3383 588 3448 588Q3508 588 3559.5 565.5Q3611 543 3645.0 502.5Q3679 462 3686 408H3565Q3555 445 3522.0 469.5Q3489 494 3443 494Q3401 494 3376.0 476.0Q3351 458 3351 429Q3351 402 3369.5 387.5Q3388 373 3418.0 364.5Q3448 356 3484.0 349.0Q3520 342 3556.0 331.5Q3592 321 3622.0 302.0Q3652 283 3670.5 250.5Q3689 218 3689 166Q3689 114 3660.0 73.5Q3631 33 3580.5 10.5Q3530 -12 3465 -12Z M3923 748V494Q3950 539 3991.5 563.5Q4033 588 4085 588Q4147 588 4194.0 562.0Q4241 536 4267.0 488.5Q4293 441 4293 375V0H4171V350Q4171 410 4138.0 444.0Q4105 478 4050 478Q3990 478 3956.5 434.5Q3923 391 3923 327V0H3801V748Z"/></g>
|
|
9
|
+
<text x="289" y="202" font-family="monospace" font-size="18" letter-spacing="3" fill="#a76bff">cli</text>
|
|
10
|
+
</svg>
|
package/assets/logo.png
CHANGED
|
Binary file
|
package/assets/logo.svg
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 518 320" role="img" aria-labelledby="title">
|
|
2
|
-
<title id="title">semrush
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<path d="m340 130 29 29-29 29m45 0h35" fill="none" stroke="black" stroke-width="12" stroke-linejoin="miter"/>
|
|
7
|
-
</mask>
|
|
8
|
-
</defs>
|
|
9
|
-
<path d="M357.481 3C333.269 3 306.873 11.7835 277.382 27.1205L113.044 114.41H247.71L3 244.524H272.376L136.164 316.977H361.44C446.818 314.792 515.038 245.48 515.038 160.011C515.038 74.5425 444.178 3.04552 357.481 3.04552V3Z" fill="#ff642d" mask="url(#terminal)"/>
|
|
2
|
+
<title id="title">semrush terminal comet</title>
|
|
3
|
+
<path d="M357.481 3C333.269 3 306.873 11.7835 277.382 27.1205L113.044 114.41H247.71L3 244.524H272.376L136.164 316.977H361.44C446.818 314.792 515.038 245.48 515.038 160.011C515.038 74.5425 444.178 3.04552 357.481 3.04552V3Z" fill="#ff642d"/>
|
|
4
|
+
<path d="M136.164 316.977L272.376 244.524H408L272 316.977Z" fill="#a76bff"/>
|
|
5
|
+
<path d="m317 116 47 44-47 44m73 0h52" fill="none" stroke="#421983" stroke-width="22" stroke-linecap="square" stroke-linejoin="miter"/>
|
|
10
6
|
</svg>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { n as SessionError, r as UsageError } from "./errors-
|
|
2
|
-
import {
|
|
1
|
+
import { n as SessionError, r as UsageError } from "./errors-DNn_XeoU.js";
|
|
2
|
+
import { a as Sessions, r as origin } from "./session-layer-Bq5OpnR5.js";
|
|
3
3
|
import "./browser-service-BYYE-vSm.js";
|
|
4
|
-
import { t as readBootstrap } from "./browser-layer-
|
|
4
|
+
import { t as readBootstrap } from "./browser-layer-gdm03TCV.js";
|
|
5
5
|
import { Config, Effect, Option } from "effect";
|
|
6
6
|
import { chromium } from "patchright";
|
|
7
7
|
|
|
@@ -79,4 +79,4 @@ const login = Effect.fn("Auth.login")(function* () {
|
|
|
79
79
|
|
|
80
80
|
//#endregion
|
|
81
81
|
export { importBrowser, login };
|
|
82
|
-
//# sourceMappingURL=auth-
|
|
82
|
+
//# sourceMappingURL=auth-CrYOA8QT.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-
|
|
1
|
+
{"version":3,"file":"auth-CrYOA8QT.js","names":["page","browser"],"sources":["../src/auth.ts"],"sourcesContent":["import { Config, Effect, Option } from 'effect';\nimport { chromium, type BrowserContext } from 'patchright';\nimport { Sessions } from './session-service.js';\nimport { origin } from './session-layer.js';\nimport { SessionError, UsageError } from './errors.js';\nimport { readBootstrap } from './browser-layer.js';\n\nconst authFailed = () => new SessionError({ message: 'Could not import a signed-in Semrush session. Check the browser, complete sign-in, and retry. No credentials were logged.' });\nconst authCall = <A>(run: () => Promise<A>) => Effect.tryPromise({ try: run, catch: authFailed });\n\nconst saveContext = Effect.fn('Auth.saveContext')(function* (context: BrowserContext) {\n const sessions = yield* Sessions;\n const page = yield* Effect.acquireRelease(authCall(() => context.newPage()), page => Effect.promise(() => page.close()));\n yield* authCall(() => page.goto(origin + '/robots.txt', { waitUntil: 'domcontentloaded', timeout: 45000 }));\n const html = yield* authCall(() => page.evaluate(async () => {\n const response = await fetch('/analytics/overview/?db=us', { credentials: 'include', signal: AbortSignal.timeout(45000) });\n return response.ok ? response.text() : '';\n }));\n yield* Effect.try({ try: () => readBootstrap(html), catch: authFailed });\n const cookies = yield* authCall(() => context.cookies(origin));\n if (!cookies.length) return yield* Effect.fail(authFailed());\n // Bare cookies are intentionally bound to the single approved origin by Galleton.\n return yield* sessions.save({ provider: 'semrush', cookie_origin: origin, cookie_header: cookies.map(cookie => `${cookie.name}=${cookie.value}`).join('; ') });\n});\n\nexport const importBrowser = Effect.fn('Auth.import')(function* (url: string) {\n const valid = yield* Effect.try({ try: () => {\n const parsed = new URL(url);\n if (parsed.protocol !== 'http:' || !['127.0.0.1', '[::1]'].includes(parsed.hostname) || parsed.username || parsed.password) throw new Error('Not loopback');\n return parsed.origin;\n }, catch: () => new UsageError({ message: 'CDP must be a literal loopback HTTP URL. Forward remote browsers over SSH first.' }) });\n const browser = yield* authCall(() => chromium.connectOverCDP(valid, { timeout: 30000 }));\n // Closing a CDP connection disconnects this client and leaves the existing browser running.\n yield* Effect.addFinalizer(() => Effect.promise(() => browser.close()));\n const context = browser.contexts()[0];\n if (!context) return yield* Effect.fail(authFailed());\n const status = yield* saveContext(context);\n return { logged_in: true, source: 'galleton', session: status.id };\n});\n\nexport const login = Effect.fn('Auth.login')(function* () {\n const executable = yield* Config.option(Config.String('SEMRUSH_BROWSER_EXECUTABLE'));\n const browser = yield* Effect.acquireRelease(authCall(() => chromium.launch({ headless: false, executablePath: Option.getOrUndefined(executable) })), browser => Effect.promise(() => browser.close()));\n const context = yield* authCall(() => browser.newContext({ userAgent: 'OpenAI File Downloader, XaiImageApiFetch/1.0' }));\n const page = yield* authCall(() => context.newPage());\n yield* authCall(() => page.goto(origin + '/login/', { waitUntil: 'domcontentloaded', timeout: 45000 }));\n yield* Effect.sync(() => process.stderr.write('Sign into Semrush in the browser. Waiting up to 5 minutes.\\n'));\n yield* authCall(() => page.waitForURL(url => url.hostname === 'www.semrush.com' && !url.pathname.startsWith('/login') && !url.pathname.startsWith('/signup'), { timeout: 300000 }));\n const status = yield* saveContext(context);\n return { logged_in: true, source: 'galleton', session: status.id };\n});\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as reportParameters, l as webRequest, n as SessionError, s as rpcBody, t as ReportError } from "./errors-
|
|
2
|
-
import {
|
|
1
|
+
import { a as reportParameters, l as webRequest, n as SessionError, s as rpcBody, t as ReportError } from "./errors-DNn_XeoU.js";
|
|
2
|
+
import { a as Sessions, r as origin } from "./session-layer-Bq5OpnR5.js";
|
|
3
3
|
import { t as Semrush } from "./browser-service-BYYE-vSm.js";
|
|
4
4
|
import { Config, Effect, Layer, Option, Predicate, Schema, Semaphore } from "effect";
|
|
5
5
|
import { chromium } from "patchright";
|
|
@@ -19,7 +19,7 @@ const json = JSONbig({
|
|
|
19
19
|
protoAction: "error",
|
|
20
20
|
constructorAction: "error"
|
|
21
21
|
});
|
|
22
|
-
const safeBrowserError = () => new ReportError({ message: "Semrush browser request failed. Run semrush
|
|
22
|
+
const safeBrowserError = () => new ReportError({ message: "Semrush browser request failed. Run semrush doctor. If your session expired, sign in again with semrush auth login." });
|
|
23
23
|
const browserCall = (run) => Effect.tryPromise({
|
|
24
24
|
try: run,
|
|
25
25
|
catch: safeBrowserError
|
|
@@ -74,7 +74,7 @@ const makeSemrushLayer = (browserOrigin) => Layer.effect(Semrush, Effect.gen(fun
|
|
|
74
74
|
}));
|
|
75
75
|
const auth = yield* Effect.try({
|
|
76
76
|
try: () => readBootstrap(bootstrap.text),
|
|
77
|
-
catch: () => new SessionError({ message: "Semrush sign-in metadata unavailable. Run semrush
|
|
77
|
+
catch: () => new SessionError({ message: "Semrush sign-in metadata unavailable. Run semrush auth login or import a signed-in browser." })
|
|
78
78
|
});
|
|
79
79
|
const semaphore = yield* Semaphore.make(1);
|
|
80
80
|
let spectrumToken = "";
|
|
@@ -83,21 +83,21 @@ const makeSemrushLayer = (browserOrigin) => Layer.effect(Semrush, Effect.gen(fun
|
|
|
83
83
|
const payload$1 = JSON.parse(encodedPayload);
|
|
84
84
|
const query = new URLSearchParams();
|
|
85
85
|
const get = method$1 === "GET";
|
|
86
|
-
if (get) for (const [key, value] of Object.entries(payload$1)) for (const item of Array.isArray(value) ? value : [value]) query.append(key, String(item));
|
|
86
|
+
if (get) for (const [key, value] of Object.entries(payload$1 ?? {})) for (const item of Array.isArray(value) ? value : [value]) query.append(key, String(item));
|
|
87
87
|
const options = {
|
|
88
88
|
method: method$1,
|
|
89
89
|
credentials: "include",
|
|
90
90
|
headers: extraHeaders$1,
|
|
91
91
|
signal: AbortSignal.timeout(45e3)
|
|
92
92
|
};
|
|
93
|
-
if (!get && method$1 !== "DELETE") {
|
|
93
|
+
if (!get && method$1 !== "DELETE" && payload$1 !== null) {
|
|
94
94
|
options.headers = {
|
|
95
95
|
...extraHeaders$1,
|
|
96
96
|
"Content-Type": "application/json"
|
|
97
97
|
};
|
|
98
98
|
options.body = JSON.stringify(payload$1);
|
|
99
99
|
}
|
|
100
|
-
const response = await fetch(get && query.size > 0 ? path$1 + "?" + query : path$1, options);
|
|
100
|
+
const response = await fetch(get && query.size > 0 ? path$1 + (path$1.includes("?") ? "&" : "?") + query : path$1, options);
|
|
101
101
|
return {
|
|
102
102
|
status: response.status,
|
|
103
103
|
text: await response.text()
|
|
@@ -124,7 +124,7 @@ const makeSemrushLayer = (browserOrigin) => Layer.effect(Semrush, Effect.gen(fun
|
|
|
124
124
|
try: () => parseWire(wire.text),
|
|
125
125
|
catch: () => new ReportError({ message: "Semrush returned a page or challenge instead of JSON. Sign in again or retry later." })
|
|
126
126
|
});
|
|
127
|
-
if (objectValue(body) && ("error" in body || "status" in body && !(body.status === null || body.status === "SUCCESS" || body.status === "success"))) return yield* Effect.fail(new ReportError({ message: `Semrush report failed: ${JSON.stringify(redact(body.error ?? body.status ?? null, [
|
|
127
|
+
if (objectValue(body) && ("error" in body || !path.startsWith("/siteaudit/") && "status" in body && !(body.status === null || body.status === "SUCCESS" || body.status === "success"))) return yield* Effect.fail(new ReportError({ message: `Semrush report failed: ${JSON.stringify(redact(body.error ?? body.status ?? null, [
|
|
128
128
|
auth.apiKey,
|
|
129
129
|
spectrumToken,
|
|
130
130
|
spectrumToken.replace(/^Bearer /, "")
|
|
@@ -159,6 +159,18 @@ const makeSemrushLayer = (browserOrigin) => Layer.effect(Semrush, Effect.gen(fun
|
|
|
159
159
|
if (!objectValue(body) || !("result" in body)) return yield* Effect.fail(new ReportError({ message: `Semrush ${method}: missing report result.` }));
|
|
160
160
|
return body.result ?? null;
|
|
161
161
|
});
|
|
162
|
+
const checkAuditSettings = Effect.fn("Semrush.checkAuditSettings")(function* (name, query) {
|
|
163
|
+
if (name === "audit_create") {
|
|
164
|
+
const campaigns = yield* request("/siteaudit/api/campaigns/seolist", { key: auth.apiKey }, "GET");
|
|
165
|
+
if (!Array.isArray(campaigns)) return yield* Effect.fail(new ReportError({ message: "Site Audit campaign discovery returned an unexpected response. No settings were saved." }));
|
|
166
|
+
if (campaigns.some((campaign) => objectValue(campaign) && String(campaign.id) === String(query.campaign_id))) return yield* Effect.fail(new ReportError({ message: "This SEO project already has a Site Audit. Use audit-configure to replace its settings explicitly." }));
|
|
167
|
+
}
|
|
168
|
+
if (name === "audit_configure") {
|
|
169
|
+
const current = yield* request(`/siteaudit/api/campaigns/${query.campaign_id}/info?key=${encodeURIComponent(auth.apiKey)}`, {}, "GET");
|
|
170
|
+
if (objectValue(current) && Predicate.isString(current.projectDomain) && current.projectDomain !== query.domain) return yield* Effect.fail(new ReportError({ message: "The audit domain must match the SEO project website. Inspect audit-info for projectDomain before configuring it." }));
|
|
171
|
+
if (objectValue(current) && (Boolean(current.authEnabled) || Boolean(current.webBotAuthEnabled) || objectValue(current.gaSettings) && Object.keys(current.gaSettings).length > 0)) return yield* Effect.fail(new ReportError({ message: "This audit uses protected-site authentication or Google Analytics. Edit its settings in the Semrush web UI to preserve those connections." }));
|
|
172
|
+
}
|
|
173
|
+
});
|
|
162
174
|
const report = Effect.fn("Semrush.report")(function* ({ name, definition, query }) {
|
|
163
175
|
if (!(yield* browserCall(() => page.evaluate(async () => {
|
|
164
176
|
const response = await fetch("/home/", {
|
|
@@ -168,9 +180,9 @@ const makeSemrushLayer = (browserOrigin) => Layer.effect(Semrush, Effect.gen(fun
|
|
|
168
180
|
signal: AbortSignal.timeout(15e3)
|
|
169
181
|
});
|
|
170
182
|
return response.ok && new URL(response.url).pathname === "/home/";
|
|
171
|
-
})))) return yield* Effect.fail(new SessionError({ message: "Semrush session expired. Run semrush
|
|
183
|
+
})))) return yield* Effect.fail(new SessionError({ message: "Semrush session expired. Run semrush auth login or import a signed-in browser." }));
|
|
172
184
|
const family = definition.transport;
|
|
173
|
-
const planned =
|
|
185
|
+
const planned = ["project_web", "audit_web"].includes(family) ? webRequest(definition, query) : void 0;
|
|
174
186
|
const params = planned?.body ?? reportParameters(definition, query);
|
|
175
187
|
let reportData;
|
|
176
188
|
if (planned) {
|
|
@@ -179,7 +191,8 @@ const makeSemrushLayer = (browserOrigin) => Layer.effect(Semrush, Effect.gen(fun
|
|
|
179
191
|
if (!objectValue(current) || !objectValue(current.folder)) return yield* Effect.fail(new ReportError({ message: "Project metadata unavailable. Inspect the project before adding a website." }));
|
|
180
192
|
if (Predicate.isString(current.folder.domain) && current.folder.domain.length > 0) return yield* Effect.fail(new ReportError({ message: "This project already has a website. The Semrush web UI only allows adding a website when none is set." }));
|
|
181
193
|
}
|
|
182
|
-
|
|
194
|
+
if (family === "audit_web") yield* checkAuditSettings(name, query);
|
|
195
|
+
reportData = yield* request(family === "audit_web" ? planned.path + "?key=" + encodeURIComponent(auth.apiKey) : planned.path, planned.body, planned.method);
|
|
183
196
|
} else if ([
|
|
184
197
|
"keyword",
|
|
185
198
|
"domain",
|
|
@@ -297,4 +310,4 @@ const captureCookies = Effect.fn("Semrush.captureCookies")(function* (context, c
|
|
|
297
310
|
|
|
298
311
|
//#endregion
|
|
299
312
|
export { semrushLive as n, readBootstrap as t };
|
|
300
|
-
//# sourceMappingURL=browser-layer-
|
|
313
|
+
//# sourceMappingURL=browser-layer-gdm03TCV.js.map
|