@nuxtseo/cli 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,8 +19,13 @@ It is available on `actions list`, `page inspect`, `page issues`, `vitals
19
19
  findings`, `backlinks recoverable`, `search analytics` row views, `search
20
20
  indexing urls`, `sitemaps urls` and `content briefs list`.
21
21
 
22
+ The `search analytics` row views are `pages`, `keywords`, `countries`,
23
+ `devices`, and `analysis`. `--all` on any other view exits `2`.
24
+
22
25
  ## Contents
23
26
 
27
+ - Which command answers which question
28
+ - One invocation for the whole Site
24
29
  - Account and Site
25
30
  - Assessment and Actions
26
31
  - Pages, Scans, and lab performance
@@ -32,11 +37,72 @@ indexing urls`, `sitemaps urls` and `content briefs list`.
32
37
  - Content Briefs, Timeline, and annotations
33
38
  - Ask the CLI for its own help
34
39
 
40
+ ## Which command answers which question
41
+
42
+ Ask one question, run one command. Stop when it is answered. Every command in
43
+ this table reads stored evidence. None of them mutates, and none of them spends
44
+ a research unit.
45
+
46
+ | Question | Command |
47
+ | --- | --- |
48
+ | Is my token valid, and what may it do | `whoami` |
49
+ | Which Site am I working on | `sites list` |
50
+ | What is wrong with this Site | `status` |
51
+ | What should I fix first | `actions list` |
52
+ | Why does this action exist | `actions show <action-id>` |
53
+ | Which exact URLs does it affect | `page issues`, with `--action-id` |
54
+ | What does NuxtSEO know about one URL | `page inspect <url>` |
55
+ | Did my last deploy break anything | `audit changes` |
56
+ | How much of the Site is indexed | `search indexing summary` |
57
+ | Which route family is Google declining | `search cohorts` |
58
+ | Why is this one URL not indexed | `search inspect <url>` |
59
+ | When did this URL change index state | `search index-history`, with `--url` |
60
+ | Which pages earn the clicks | `search analytics pages` |
61
+ | Which terms is the Site visible for | `search analytics keywords` |
62
+ | Which pages are losing clicks | `audit content-decay` |
63
+ | Where does internal link equity go | `audit link-structure` |
64
+ | Is the Site slow for real users | `vitals summary`, then `vitals findings` |
65
+ | Is the Site slow in the lab | `performance`, then `scans list` |
66
+ | Which lab check failed | `scans show <scan-id>` |
67
+ | Have I spent my limits | `usage` |
68
+
69
+ Start at `status` for a Site you do not know. It carries the verdict and one
70
+ ranked Next Action, so it replaces several of the rows below it.
71
+
72
+ ## One invocation for the whole Site
73
+
74
+ | Command | What it returns, and its flags |
75
+ | --- | --- |
76
+ | `pull` | Every stored-evidence read for one Site, as NDJSON on stdout. One complete protocol envelope per line, with the `command` it came from beside `data` and `meta`. Requires `--json`. `--include` and `--exclude` take comma separated command names or a command prefix, for example `audit`. `--with-research` adds the reads that can start live research. `--period 7d\|28d\|3m\|6m\|12m` sets the Search Console window. `--concurrency 1..8` (default 4) |
77
+
78
+ Read this first when you need the whole picture. It replaces about forty single
79
+ reads with one invocation.
80
+
81
+ `pull` excludes every mutation, and every read that needs an argument it cannot
82
+ invent, such as `page inspect`, `page issues`, `search inspect`, `actions show`,
83
+ `scans show` and `content briefs show`. Run those yourself with the IDs `pull`
84
+ returned.
85
+
86
+ `pull` makes one request per read. It never follows pages, so a run costs
87
+ exactly as many requests as it names on stderr. When a line reports more pages,
88
+ run that one command again with `--all`.
89
+
90
+ One failing read does not stop the run. It writes its error envelope on its own
91
+ line and the others continue. The exit code reports the worst outcome, and the
92
+ last line is a `CliError` value with `command: "pull"` that repeats it. An
93
+ authentication failure stops the run early, because every later read would fail
94
+ the same way.
95
+
96
+ Progress, warnings and the spend notice go to stderr. Line order follows
97
+ completion, not the catalogue, so read the `command` field rather than counting
98
+ lines.
99
+
35
100
  ## Account and Site
36
101
 
37
102
  | Command | What it returns, and its flags |
38
103
  | --- | --- |
39
104
  | `whoami` | Credential, Team, role, granted scopes, token expiry. The cheapest health check. Reads no Site |
105
+ | `feedback submit` | Submit sanitized agent feedback. Requires `--command` (1..200 characters), `--comment` (1..2000), `--agent` (1..100), and `--yes`. Optional `--intent bug\|improvement` (default `bug`) and `--request-id` (1..128). Adds the CLI version. Needs no Site. Returns the feedback ID and status |
40
106
  | `login` | Pairs the CLI with a Team through the browser. A person must approve the pairing, so ask the user to run it. `--with-token` reads a token from a hidden prompt or stdin. `--no-browser` skips opening the browser |
41
107
  | `logout` | Discards the stored credential. Returns a `CliLogout` value |
42
108
  | `sites list` | Every accessible Site. The source of Site IDs |
@@ -83,7 +149,7 @@ indexing urls`, `sitemaps urls` and `content briefs list`.
83
149
  | Command | What it returns, and its flags |
84
150
  | --- | --- |
85
151
  | `search status` | Stored Search Console connection state. Provider free. Never waits for Google |
86
- | `search analytics <view>` | Search Console rows, trend, detail, or analysis. Views: `pages`, `keywords`, `countries`, `devices`, `timeseries`, `page-detail`, `keyword-detail`, `analysis`. `--period`, `--limit`, `--page`, `--search`, `--sort`, `--filter`, `--min-clicks`, `--max-clicks`, `--min-impressions`, `--max-impressions`, `--min-position`, `--max-position`, `--max-ctr`. The `analysis` view needs `--preset`, and the brand presets also need `--brand-terms` |
152
+ | `search analytics <view>` | Search Console rows, trend, detail, or analysis. Views: `pages`, `keywords`, `countries`, `devices`, `timeseries`, `page-detail`, `keyword-detail`, `analysis`. `--period 7d\|28d\|3m\|6m\|12m` (default `28d`). No other period value is accepted; `90d` exits `2`, and `3m` is the three-month window. `--limit 1..100` (default 25), `--page` (default 1), `--search`, `--sort clicks\|impressions\|ctr\|position` (default `clicks`), `--sort-dir asc\|desc` (default `desc`), `--filter top-level\|new\|lost\|improving\|declining`, `--min-clicks`, `--max-clicks`, `--min-impressions`, `--max-impressions`, `--min-position 1..100`, `--max-position 1..100`, `--max-ctr 0..1`. The `page-detail` view needs `--page-url`, `keyword-detail` needs `--keyword`, and `analysis` needs `--preset`. The brand presets also need `--brand-terms` |
87
153
  | `search indexing <summary\|urls>` | Retained URL Inspection coverage. `summary` returns indexed counts. `urls` supports `--issue`, `--status`, `--limit 1..500` (default 50), `--offset` |
88
154
  | `search index-history` | Retained indexing changes and candidate causes. `--url`, `--field`, `--days 1..730`. Dates a regression against a release |
89
155
  | `search inspect <url>` | Google's own verdict for one URL. Takes an absolute URL or a site-relative path |
@@ -98,11 +164,37 @@ Analysis presets for `search analytics analysis` are `striking-distance`,
98
164
  `movers-rising`, and `movers-declining`. `brand-only` and `non-brand` also need
99
165
  `--brand-terms`. A missing argument exits `2` before any request.
100
166
 
167
+ ### Three totals on one `search analytics` response
168
+
169
+ The `pages`, `keywords`, `countries`, and `devices` views return three
170
+ different numbers. Read the one that answers your question.
171
+
172
+ | Field | What it counts |
173
+ | --- | --- |
174
+ | `total` | The number of rows the query matched, not clicks or impressions |
175
+ | `totals` | Clicks, impressions, CTR and position for the full upstream query population. `totalsScope` says so in words. It may include rows outside this page. `null` when the server has no total |
176
+ | `representedTotals` | Clicks and impressions for the rows in this response only, after local filtering. `representedTotalsScope` says so in words |
177
+
178
+ So `representedTotals` is at or below `totals`, and raising `--limit` moves
179
+ `representedTotals` while leaving `totals` still. Never sum `rows` by hand when
180
+ `totals` is present.
181
+
182
+ ### Never compare a keyword total with a page total
183
+
184
+ Google suppresses query rows below a privacy threshold. So the `keywords` view
185
+ sees a fraction of the traffic the `pages` view sees. On a typical property
186
+ that is roughly half the impressions. Query-dimension totals are therefore
187
+ always at or below page-dimension totals for the same Site and period. Never
188
+ compare the two, and never report one as the Site total.
189
+
190
+ Read the `pages` view for "how much traffic". Read the `keywords` view for
191
+ "which terms are visible". A missing query row is never evidence of no demand.
192
+
101
193
  ## Web Analytics
102
194
 
103
195
  | Command | What it returns, and its flags |
104
196
  | --- | --- |
105
- | `analytics <view>` | Web Analytics from the connected provider. Views: `performance`, `top-pages`, `source-medium`, `key-events`, `countries`, `devices`, `dimension`. `--period`, `--compare`, `--dimension`, `--filters` |
197
+ | `analytics <view>` | Web Analytics from the connected provider. Views: `performance`, `top-pages`, `source-medium`, `key-events`, `countries`, `devices`, `dimension`. `--period` is a free string, for example `28d` (default `28d`); an empty value exits `2`. `--compare previous\|year\|none` (default `previous`), `--dimension` (required for the `dimension` view; one of `date`, `page`, `hostname`, `source`, `medium`, `campaign`, `country`, `region`, `city`, `deviceCategory`, `browser`, `operatingSystem`), `--filters` as a JSON array, `--phase current\|prior\|full` (default `full`), `--no-stable-data` to include unstable recent days, `--no-host-scope` to include every host, `--no-compare-prior` to skip the prior window, `--fresh` to bypass the server cache |
106
198
 
107
199
  ## Research, backlinks, and mentions
108
200
 
@@ -112,28 +204,28 @@ research boundary in SKILL.md first.
112
204
 
113
205
  | Command | What it returns, and its flags |
114
206
  | --- | --- |
115
- | `research overview` | Stored Site and competitor research: metrics, history, gaps, quick wins |
116
- | `research keywords <topic>` | Live keyword ideas, with volume, difficulty, intent, and cost data |
117
- | `research serp <keyword>` | A live SERP snapshot: results, features, fetch time |
118
- | `research rankings <domain>` | Live domain rankings: current keywords and domain metrics |
207
+ | `research overview` | Stored Site and competitor research: metrics, history, gaps, quick wins. Takes no flags. Returns `data.competitors` and `data.summary` |
208
+ | `research keywords <topic>` | Live keyword ideas, with volume, difficulty, intent, and cost data. The seed must be 1 to 3 words. The server refuses a longer seed. The refusal arrives as exit `0` with an empty `data.keywords`, so read `data.message` first. Comma-separate several short seeds instead. Special characters are stripped before the lookup. If a seed is under 2 characters after stripping, the server refuses it the same way. The server applies default filters and echoes them in `data.filters`: `--min-volume` (default 10), `--max-volume` (default 10000), `--min-difficulty 0..100` (default 0), `--max-difficulty 0..100` (default 60). So a default run hides keywords over difficulty 60 or under 10 searches. Also `--limit 1..100` (default 20), `--intent`, `--location-code` (default 2840), `--no-related` to drop related keywords, and `--verbose` for full evidence. If `--max-volume` is under `--min-volume`, the run exits `2`. The same holds for `--max-difficulty` under `--min-difficulty` |
209
+ | `research serp <keyword>` | A live SERP snapshot: results, features, fetch time. `--depth 1..20` (default 10) sets how many organic results return. `--location-code` (default 2840). The keyword must be 2 to 200 characters. `data.cached` reports cache use |
210
+ | `research rankings <domain>` | Live domain rankings: current keywords and domain metrics. `--limit 1..100` (default 50), `--min-position 1..100` (default 1), `--max-position 1..100` (default 20), `--location-code` (default 2840), `--order position\|traffic` (default `position`). So a default run returns only the top 20 positions. If `--max-position` is under `--min-position`, the run exits `2`. An unusable domain also exits `2`, with `invalid_request`. An empty `data.keywords` with exit `0` carries the reason in `data.message`. `data.cached` reports cache use |
119
211
  | `research domain-traffic <domain>` | A live organic traffic estimate for any domain: trend, top pages, top countries. The domain does not have to be one of your Sites |
120
212
  | `research domain-availability <domains>` | Registration status. One comma-separated positional, up to 10 domains |
121
- | `backlinks summary` | Whole-domain inbound link totals. `evidence` reports cache use. Needs a Site URL |
213
+ | `backlinks summary` | Whole-domain inbound link totals for the Site's own domain: `backlinks`, `referringDomains`, `referringPages`, `brokenBacklinks`, `brokenPages`, `crawledPages`, `spamScore`, `rank`. Takes no flags; it always reads the registered Site URL, so use `research domain-traffic` for any other domain. Every count is nullable. A `null` count means the provider returned no value. Never read it as zero. `evidence` reports cache use. Needs a Site URL |
122
214
  | `backlinks referring-domains` | Domains that link to the Site. `--limit 1..1000` (default 100). `sessions` is 90-day referral traffic, or null when no Web Analytics property is linked. Needs a Site URL |
123
215
  | `backlinks anchors` | Anchor text distribution of inbound links. `--limit 1..1000` (default 100). Needs a Site URL |
124
216
  | `backlinks history` | A monthly inbound link series. `--from YYYY-MM-DD`. Defaults to about twelve months. Needs a Site URL |
125
217
  | `backlinks recoverable` | Stored recoverable backlinks. `--limit 1..200`, `--offset`. Reads retained rows |
126
- | `mentions list` | Stored mentions. `--limit 1..200`. Reads retained rows |
218
+ | `mentions list` | Stored mentions. `--limit 1..200` (default 100), `--include-filtered` to keep the Mentions AI triage marked a false positive. Reads retained rows |
127
219
 
128
220
  ## Crawl audit
129
221
 
130
222
  | Command | What it returns, and its flags |
131
223
  | --- | --- |
132
224
  | `audit changes` | The latest crawl compared with its baseline. `--from`, `--to`. The read for "did my deploy break anything" |
133
- | `audit link-opportunities` | Stored internal link opportunities, with crawl coverage |
134
- | `audit link-structure` | Template links, dead ends, and generic anchors. Shows where link equity goes |
135
- | `audit content-decay` | Stored decaying Pages, with Search Console loss evidence |
136
- | `audit duplicates` | Stored duplicate clusters, with members and keep candidate |
225
+ | `audit link-opportunities` | Stored internal link opportunities, with crawl coverage. Takes no flags. Read `connected` and `pagesScanned` before quoting `total` |
226
+ | `audit link-structure` | Template links, dead ends, and generic anchors. Shows where link equity goes. Takes no flags. It returns three separate lists: `templateSlots`, `deadEnds`, and `genericAnchors`. Each carries its own total. `deadEndScanTruncated: true` marks the dead-end list as a floor |
227
+ | `audit content-decay` | Stored decaying Pages, with Search Console loss evidence. Takes no flags. If `connected` is `false`, the Site has no Search Console data. Never report that as clean. `truncated: true` marks the list as a floor |
228
+ | `audit duplicates` | Stored duplicate clusters, with members and keep candidate. Takes no flags. `crawlSettingsId: null` means the Site never completed a crawl. Then `total: 0` proves nobody looked. Never report it as a clean Site |
137
229
 
138
230
  ## Content Briefs, Timeline, and annotations
139
231
 
@@ -18,6 +18,29 @@ Protocol failure, still on stdout, with recovery details on stderr:
18
18
 
19
19
  Read `data`. The CLI does not unwrap, rename, rank, or enrich fields.
20
20
 
21
+ ## A soft failure looks like an empty result
22
+
23
+ Some commands refuse the argument and still exit `0` with an empty list. The
24
+ reason sits in `data.message`. A repair hint sits in `data.tip`. Read both
25
+ before you read the list. Otherwise you report "nothing found" for a request
26
+ the server never ran.
27
+
28
+ These fields carry the reason:
29
+
30
+ | Command | Fields |
31
+ | --- | --- |
32
+ | `research keywords` | `data.message`, `data.tip` |
33
+ | `research rankings` | `data.message` |
34
+ | `research domain-traffic` | `data.message` |
35
+ | `research domain-availability` | `data.message` |
36
+ | `page issues` | `data.message`, plus `availableKeys` |
37
+ | `search cohorts` | `data.message`, plus `reason` |
38
+ | `vitals findings` | `data.message`, plus `source` |
39
+
40
+ `evidence._tag: "no-provider"` does not prove the data is absent. On `research
41
+ keywords` it also marks a refused argument. The provider was never asked. Read
42
+ `data.message` to tell the two cases apart.
43
+
21
44
  Local outcomes have no server body. They carry one tag and their own schema
22
45
  version. `CliHelp` uses version 2. The other values use version 1.
23
46
 
@@ -58,6 +81,10 @@ One invocation makes one request by default. The CLI never merges responses.
58
81
  writes one complete envelope per page, newline delimited, so parse the stream
59
82
  one JSON value per line. Nothing is merged, unwrapped, or re-ranked.
60
83
 
84
+ `pull` writes the same stream for a whole Site. Each line is one operation's
85
+ envelope with a `command` field beside `data` and `meta`. `pull` makes one
86
+ request per operation and never follows pages, so it needs no cap of its own.
87
+
61
88
  The `--all` loop stops after 50 requests. If pages remain, the CLI exits `9`
62
89
  and stderr names the argument that resumes the read, for example `--offset 50`.
63
90
  Treat exit `9` as a stop, never as the end of the data.
@@ -65,6 +92,50 @@ Treat exit `9` as a stop, never as the end of the data.
65
92
  Pass the reported `offset` or opaque `cursor` for another page. Never edit or
66
93
  infer a cursor. Keep server order for actions. Never re-rank merged results.
67
94
 
95
+ ## List key and paging shape per command
96
+
97
+ There is no single list key. Read the key this command returns; never guess a
98
+ chain. Verified against the response schemas.
99
+
100
+ | Command | List key | Paging fields |
101
+ | --- | --- | --- |
102
+ | `sites list` | `data.sites` | none; `meta.total` |
103
+ | `usage` | `data.meters` | none |
104
+ | `actions list` | `data.actions` | `data.page.total`, `.limit`, `.offset`, `.hasMore` |
105
+ | `actions show` | `data.evidenceGroups[].items` | `data.evidenceGroups[].nextCursor` |
106
+ | `page inspect` | `data.observations.rows` | `data.observations.total` and `data.observations.pagination.limit`, `.offset`, `.hasMore` |
107
+ | `page issues` | `data.issues` | `data.total`, `data.limit`, `data.offset` |
108
+ | `scans list` | `data.scans` | `data.total`, `data.limit` |
109
+ | `scans pages` | `data.pages` | `data.total` |
110
+ | `vitals findings` | `data.findings` | `data.total`, `data.limit`, `data.offset` |
111
+ | `search analytics` row views | `data.rows` | `data.total`; page with `--page` |
112
+ | `search analytics timeseries` | `data.daily` | none |
113
+ | `search indexing urls` | `data.urls` | `data.total`, `data.limit`, `data.offset`, `data.hasMore` |
114
+ | `search index-history` | `data.changes` | none |
115
+ | `search cohorts` | `data.established` and `data.ranked` | `data.rankedTotal` |
116
+ | `sitemaps list` | `data.sitemaps` | none |
117
+ | `sitemaps urls` | `data.items` | `data.page.nextCursor`, `data.page.limit` |
118
+ | `audit content-decay` | `data.rows` | `data.total`, `data.truncated` |
119
+ | `audit link-opportunities` | `data.rows` | `data.total` |
120
+ | `audit duplicates` | `data.clusters` | `data.total` |
121
+ | `audit link-structure` | `data.templateSlots`, `data.deadEnds`, `data.genericAnchors` | one total per list |
122
+ | `research keywords` | `data.keywords` | `data.totalFound` |
123
+ | `research serp` | `data.results` | none; `data.depth` |
124
+ | `research rankings` | `data.keywords` | `data.totalFound` |
125
+ | `research domain-availability` | `data.results` | none |
126
+ | `backlinks referring-domains` | `data.items` | `data.total`, `data.limit` |
127
+ | `backlinks anchors` | `data.items` | `data.total`, `data.limit` |
128
+ | `backlinks history` | `data.items` | `data.total` |
129
+ | `backlinks recoverable` | `data.items` | `data.total`, `data.limit`, `data.offset` |
130
+ | `mentions list` | `data.items` | `data.limit` |
131
+ | `content briefs list` | `data.briefs` | `data.page.total`, `.limit`, `.offset`, `.hasMore` |
132
+ | `timeline list` | `data.entries` | `data.nextCursor` |
133
+ | `annotations list` | `data.annotations` | `data.total`, `data.limit` |
134
+
135
+ Four paging shapes appear above: a nested `data.page` object, flat `total`,
136
+ `limit` and `offset` fields, an opaque `nextCursor`, and no paging at all. The
137
+ table is today's reality, so re-read it after a CLI update.
138
+
68
139
  ## Exit codes
69
140
 
70
141
  Branch on the exit code, not message text.
@@ -77,7 +148,7 @@ Branch on the exit code, not message text.
77
148
  | `4` | Forbidden, scope, or entitlement failure | Report the plan or token blocker |
78
149
  | `5` | Conflict, stale evidence, or ambiguous Site | Re-read. Pass `--site` if ambiguous |
79
150
  | `6` | Rate limit, `quota_exhausted`, provider outage, or timeout | Read retry metadata, then wait |
80
- | `7` | Local state, network, contract, or infrastructure failure | Report it with the request ID. If the message names `contract_violation`, update the CLI first |
151
+ | `7` | Local state, network, contract, or infrastructure failure | Report it with the request ID. If the message names `contract_violation`, follow its contract version lines |
81
152
  | `8` | Resource or Site not found | Run `sites list` for a valid Site ID |
82
153
  | `9` | `--all` reached its request cap | Resume with the argument stderr names |
83
154
  | `127` | Shell cannot find `nuxtseo` | Install the CLI |