@nuxtseo/cli 0.5.9 → 0.5.11
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 +12 -6
- package/dist/commands.js +31 -10
- package/dist/render.d.ts +2 -5
- package/dist/render.js +45 -1
- package/package.json +3 -3
- package/skills/nuxtseo-cli/SKILL.md +14 -2
- package/skills/nuxtseo-cli/references/commands.md +19 -7
- package/skills/nuxtseo-cli/references/protocol.md +23 -1
package/README.md
CHANGED
|
@@ -195,6 +195,8 @@ nuxtseo annotations create
|
|
|
195
195
|
nuxtseo annotations update <annotation-id>
|
|
196
196
|
nuxtseo annotations delete <annotation-id>
|
|
197
197
|
nuxtseo analytics <view>
|
|
198
|
+
nuxtseo bot-traffic --crawler googlebot
|
|
199
|
+
nuxtseo bot-traffic --crawler bingbot
|
|
198
200
|
nuxtseo search status
|
|
199
201
|
nuxtseo search analytics <view>
|
|
200
202
|
nuxtseo search indexing <summary|urls>
|
|
@@ -343,9 +345,9 @@ The CLI never falls back to MCP, a private route, or cached feature data.
|
|
|
343
345
|
|
|
344
346
|
### Claim response
|
|
345
347
|
|
|
346
|
-
`actions resolve` saves your Claim. It returns before
|
|
348
|
+
`actions resolve` saves your Claim. It returns before verification completes.
|
|
347
349
|
`status: "open"` stays unchanged until the engine verifies the Action.
|
|
348
|
-
Human output shows `Claimed, verifying
|
|
350
|
+
Human output shows `Claimed, verifying`.
|
|
349
351
|
Claimed Actions leave `actions list`. Use `actions show <action-id>` to check them.
|
|
350
352
|
|
|
351
353
|
Both `resolve` and `show` return these additive fields:
|
|
@@ -353,8 +355,12 @@ Both `resolve` and `show` return these additive fields:
|
|
|
353
355
|
| Field | Meaning |
|
|
354
356
|
| --- | --- |
|
|
355
357
|
| `markedAt` | ISO timestamp when your Claim was saved, or `null` before a Claim. |
|
|
356
|
-
| `checkBackAt` |
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
`scan-queued`
|
|
358
|
+
| `checkBackAt` | Supported ISO timestamp to check again, or `null` when the schedule is unknown. |
|
|
359
|
+
|
|
360
|
+
`recheck-queued` requests a fresh check of the cited URLs.
|
|
361
|
+
`scan-queued` means a source refresh is queued or already running.
|
|
362
|
+
`next-assessment` waits for a site check, which can reuse stored results.
|
|
363
|
+
An assessment can already be queued without requesting fresh Crawl collection.
|
|
364
|
+
Unknown check times stay null, including retries and later reads.
|
|
365
|
+
A supported check-back time does not promise completed verification.
|
|
360
366
|
A self-resolved Claim returns `status: "verified"` and `verification: "user-resolved"`.
|
package/dist/commands.js
CHANGED
|
@@ -9,7 +9,7 @@ import { EXIT_CODE, fail, fromSdkFailure, ok } from './failures.js';
|
|
|
9
9
|
import { awaitPairingApproval, createCliPairingClient, startPairing } from './pairing.js';
|
|
10
10
|
import { parseAbsolutePageUrl, parseChoice, parseInteger, parsePageUrlOrPath, parseRatio } from './parse.js';
|
|
11
11
|
import { PULL_PERIODS, runPull } from './pull.js';
|
|
12
|
-
import { renderAccountToken, renderAction, renderActionDismissal, renderActionResolution, renderActions, renderAnalytics, renderAnnotation, renderAnnotationDeleted, renderAnnotations, renderAuditChanges, renderBacklinkAnchors, renderBacklinksHistory, renderBacklinksSummary, renderContentDecay, renderDomainAvailability, renderDomainTraffic, renderDuplicateClusters, renderFieldVitalFindings, renderFieldVitals, renderIndexCohorts, renderIndexingDiagnostics, renderIndexingHistory, renderIndexingWatches, renderKeywordResearch, renderLinkOpportunities, renderLinkStructure, renderMentions, renderMonitoredPages, renderPageInspection, renderPageIssues, renderPageScan, renderPerformance, renderRankingsResearch, renderRecoverableBacklinks, renderReferringDomains, renderResearchOverview, renderScanDetail, renderScans, renderSearchAnalytics, renderSearchStatus, renderSerpResearch, renderSitemapAction, renderSitemapEvidence, renderSitemaps, renderSitemapSubmission, renderSitemapUrls, renderSites, renderSiteStatus, renderTimeline, renderUrlInspection, renderUrlInspectionRefresh, renderUsage, } from './render.js';
|
|
12
|
+
import { renderAccountToken, renderAction, renderActionDismissal, renderActionResolution, renderActions, renderAnalytics, renderAnnotation, renderAnnotationDeleted, renderAnnotations, renderAuditChanges, renderBacklinkAnchors, renderBacklinksHistory, renderBacklinksSummary, renderBotTraffic, renderContentDecay, renderDomainAvailability, renderDomainTraffic, renderDuplicateClusters, renderFieldVitalFindings, renderFieldVitals, renderIndexCohorts, renderIndexingDiagnostics, renderIndexingHistory, renderIndexingWatches, renderKeywordResearch, renderLinkOpportunities, renderLinkStructure, renderMentions, renderMonitoredPages, renderPageInspection, renderPageIssues, renderPageScan, renderPerformance, renderRankingsResearch, renderRecoverableBacklinks, renderReferringDomains, renderResearchOverview, renderScanDetail, renderScans, renderSearchAnalytics, renderSearchStatus, renderSerpResearch, renderSitemapAction, renderSitemapEvidence, renderSitemaps, renderSitemapSubmission, renderSitemapUrls, renderSites, renderSiteStatus, renderTimeline, renderUrlInspection, renderUrlInspectionRefresh, renderUsage, } from './render.js';
|
|
13
13
|
import { writeCliResponse, writeDiagnostic, writeOutput, writeProtocolResponse } from './runtime.js';
|
|
14
14
|
import { resolveSite } from './site.js';
|
|
15
15
|
import { installSkill, SKILL_AGENTS } from './skill.js';
|
|
@@ -1360,6 +1360,22 @@ async function backlinksHistory(runtime, globals, args) {
|
|
|
1360
1360
|
}, { signal: runtime.requestSignal }));
|
|
1361
1361
|
return present(runtime, globals, response, value => renderBacklinksHistory(value.data));
|
|
1362
1362
|
}
|
|
1363
|
+
async function googlebotActivity(runtime, globals, args) {
|
|
1364
|
+
const days = parseInteger(args.days, { name: '--days', minimum: 1, maximum: 90, defaultValue: 28 });
|
|
1365
|
+
if (days._tag === 'Err')
|
|
1366
|
+
return days;
|
|
1367
|
+
const crawler = parseChoice(args.crawler, { name: '--crawler', choices: ['googlebot', 'bingbot'], defaultValue: 'googlebot' });
|
|
1368
|
+
if (crawler._tag === 'Err')
|
|
1369
|
+
return crawler;
|
|
1370
|
+
const resolved = await apiAndSite(runtime, globals);
|
|
1371
|
+
if (resolved._tag === 'Err')
|
|
1372
|
+
return resolved;
|
|
1373
|
+
const response = await withSpinner(runtime, 'Loading Bot Traffic', () => resolved.value.api.client.analytics.botActivity({
|
|
1374
|
+
params: { siteId: resolved.value.siteId },
|
|
1375
|
+
query: { days: days.value, crawler: crawler.value },
|
|
1376
|
+
}, { signal: runtime.requestSignal }));
|
|
1377
|
+
return present(runtime, globals, response, value => renderBotTraffic(value.data));
|
|
1378
|
+
}
|
|
1363
1379
|
async function siteStatus(runtime, globals) {
|
|
1364
1380
|
const resolved = await apiAndSite(runtime, globals);
|
|
1365
1381
|
if (resolved._tag === 'Err')
|
|
@@ -2319,7 +2335,7 @@ export function createRootCommand(runtime, globals, execution) {
|
|
|
2319
2335
|
'yes': { type: 'boolean', alias: 'y', description: 'Confirm a mutation without prompting' },
|
|
2320
2336
|
},
|
|
2321
2337
|
subCommands: {
|
|
2322
|
-
login: defineCommand({
|
|
2338
|
+
'login': defineCommand({
|
|
2323
2339
|
meta: { name: 'login', description: 'Approve this machine in a browser and store the Team API token it mints' },
|
|
2324
2340
|
args: {
|
|
2325
2341
|
'with-token': { type: 'boolean', description: 'Paste an existing Team API token instead of pairing' },
|
|
@@ -2332,20 +2348,20 @@ export function createRootCommand(runtime, globals, execution) {
|
|
|
2332
2348
|
noBrowser: args.browser === false,
|
|
2333
2349
|
}), args._, 0)(),
|
|
2334
2350
|
}),
|
|
2335
|
-
logout: defineCommand({
|
|
2351
|
+
'logout': defineCommand({
|
|
2336
2352
|
meta: { name: 'logout', description: 'Remove the local credential' },
|
|
2337
2353
|
run: ({ args }) => capture(execution, () => logout(runtime, globals), args._, 0)(),
|
|
2338
2354
|
}),
|
|
2339
|
-
whoami: defineCommand({
|
|
2355
|
+
'whoami': defineCommand({
|
|
2340
2356
|
meta: { name: 'whoami', description: 'Validate and describe the active credential' },
|
|
2341
2357
|
run: ({ args }) => capture(execution, () => whoami(runtime, globals), args._, 0)(),
|
|
2342
2358
|
}),
|
|
2343
|
-
config: defineCommand({
|
|
2359
|
+
'config': defineCommand({
|
|
2344
2360
|
meta: { name: 'config', description: 'Show or edit local configuration' },
|
|
2345
2361
|
run: ({ args }) => capture(execution, () => config(runtime, globals), args._, 0)(),
|
|
2346
2362
|
}),
|
|
2347
2363
|
sites,
|
|
2348
|
-
feedback: defineCommand({
|
|
2364
|
+
'feedback': defineCommand({
|
|
2349
2365
|
meta: { name: 'feedback', description: 'Report CLI problems to Nuxt SEO' },
|
|
2350
2366
|
subCommands: {
|
|
2351
2367
|
submit: defineCommand({
|
|
@@ -2367,7 +2383,7 @@ export function createRootCommand(runtime, globals, execution) {
|
|
|
2367
2383
|
}),
|
|
2368
2384
|
},
|
|
2369
2385
|
}),
|
|
2370
|
-
usage: defineCommand({
|
|
2386
|
+
'usage': defineCommand({
|
|
2371
2387
|
meta: { name: 'usage', description: 'Read Team usage' },
|
|
2372
2388
|
args: {
|
|
2373
2389
|
group: {
|
|
@@ -2383,22 +2399,27 @@ export function createRootCommand(runtime, globals, execution) {
|
|
|
2383
2399
|
backlinks,
|
|
2384
2400
|
mentions,
|
|
2385
2401
|
page,
|
|
2386
|
-
performance: defineCommand({
|
|
2402
|
+
'performance': defineCommand({
|
|
2387
2403
|
meta: { name: 'performance', description: 'Read the stored Site performance overview' },
|
|
2388
2404
|
run: ({ args }) => capture(execution, () => performance(runtime, globals), args._, 0)(),
|
|
2389
2405
|
}),
|
|
2390
2406
|
annotations,
|
|
2407
|
+
'bot-traffic': defineCommand({
|
|
2408
|
+
meta: { name: 'bot-traffic', description: 'Read verified search engine requests from the Site\'s Cloudflare zone' },
|
|
2409
|
+
args: { days: { type: 'string', description: 'UTC days to read, 1 to 90, today included' }, crawler: { type: 'string', description: 'googlebot or bingbot', default: 'googlebot' } },
|
|
2410
|
+
run: ({ args }) => capture(execution, () => googlebotActivity(runtime, globals, { days: args.days, crawler: args.crawler }), args._, 0)(),
|
|
2411
|
+
}),
|
|
2391
2412
|
pull,
|
|
2392
2413
|
research,
|
|
2393
2414
|
scans,
|
|
2394
2415
|
search,
|
|
2395
2416
|
sitemaps,
|
|
2396
|
-
status: defineCommand({
|
|
2417
|
+
'status': defineCommand({
|
|
2397
2418
|
meta: { name: 'status', description: 'Read the Site assessment and the one thing to do next' },
|
|
2398
2419
|
run: ({ args }) => capture(execution, () => siteStatus(runtime, globals), args._, 0)(),
|
|
2399
2420
|
}),
|
|
2400
2421
|
vitals,
|
|
2401
|
-
analytics: defineCommand({
|
|
2422
|
+
'analytics': defineCommand({
|
|
2402
2423
|
meta: { name: 'analytics', description: 'Read Web Analytics for the selected Site' },
|
|
2403
2424
|
args: {
|
|
2404
2425
|
'view': positional('view', ANALYTICS_VIEWS.join(', ')),
|
package/dist/render.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AccountUsageResponse, SitesListResponse, SiteStatus } from '@nuxtseo/protocol/v1';
|
|
2
2
|
import type { AccountTokenData } from '@nuxtseo/protocol/v1/account';
|
|
3
3
|
import type { ActionDismiss, ActionList, ActionResolve, ActionShow } from '@nuxtseo/protocol/v1/actions';
|
|
4
|
-
import type { AnalyticsQueryData, AnalyticsView } from '@nuxtseo/protocol/v1/analytics';
|
|
4
|
+
import type { AnalyticsQueryData, AnalyticsView, BotActivity } from '@nuxtseo/protocol/v1/analytics';
|
|
5
5
|
import type { AuditChanges, AuditContentDecay, AuditDuplicateClusters, AuditLinkOpportunities, AuditLinkStructure } from '@nuxtseo/protocol/v1/audit';
|
|
6
6
|
import type { BacklinkAnchorsData, BacklinksHistory, BacklinksSummaryData, MentionsData, RecoverableBacklinksData, ReferringDomainsData } from '@nuxtseo/protocol/v1/backlinks';
|
|
7
7
|
import type { IndexCohorts, IndexingDiagnosticsData, IndexingHistoryData, IndexingWatchesData, SearchAnalyticsData, SearchStatusData, UrlInspectionData, UrlInspectionRefreshData } from '@nuxtseo/protocol/v1/gsc';
|
|
@@ -31,10 +31,7 @@ export declare function renderIndexingWatches(data: IndexingWatchesData): string
|
|
|
31
31
|
export declare function renderSitemaps(data: SiteSitemapsResponse['data']): string;
|
|
32
32
|
export declare function renderSitemapUrls(data: SiteSitemapUrlsResponse['data']): string;
|
|
33
33
|
export declare function renderSitemapAction(data: SiteSitemapActionResponse['data']): string;
|
|
34
|
-
|
|
35
|
-
* Web Analytics rows differ per view and share no discriminant field, so the
|
|
36
|
-
* requested view selects the projection instead of the payload.
|
|
37
|
-
*/
|
|
34
|
+
export declare function renderBotTraffic(data: BotActivity): string;
|
|
38
35
|
export declare function renderAnalytics(view: AnalyticsView, data: AnalyticsQueryData): string;
|
|
39
36
|
export declare function renderAccountToken(data: AccountTokenData): string;
|
|
40
37
|
export declare function renderIndexingDiagnostics(data: IndexingDiagnosticsData): string;
|
package/dist/render.js
CHANGED
|
@@ -433,6 +433,48 @@ export function renderSitemapAction(data) {
|
|
|
433
433
|
* Web Analytics rows differ per view and share no discriminant field, so the
|
|
434
434
|
* requested view selects the projection instead of the payload.
|
|
435
435
|
*/
|
|
436
|
+
function percent(share) {
|
|
437
|
+
return share === null ? 'none' : `${(share * 100).toFixed(1)}%`;
|
|
438
|
+
}
|
|
439
|
+
function googlebotAccessLines(access) {
|
|
440
|
+
if (access._tag === 'zone_access_missing') {
|
|
441
|
+
return [
|
|
442
|
+
`Collection stopped: ${access.message}`,
|
|
443
|
+
`Grant: ${access.permissions.join(', ')} (OAuth: ${access.oauthScopes.join(', ')})`,
|
|
444
|
+
];
|
|
445
|
+
}
|
|
446
|
+
if (access._tag === 'collection_failed')
|
|
447
|
+
return [`Collection stopped (${access.reason}): ${access.message}`];
|
|
448
|
+
return [];
|
|
449
|
+
}
|
|
450
|
+
export function renderBotTraffic(data) {
|
|
451
|
+
const access = googlebotAccessLines(data.access);
|
|
452
|
+
const crawler = data.crawler === 'googlebot' ? 'Googlebot' : 'Bingbot';
|
|
453
|
+
if (data.collection === null)
|
|
454
|
+
return [...access, `No ${crawler} requests collected yet. Collection runs with the Site's Cloudflare sync.`].join('\n');
|
|
455
|
+
const { totals } = data;
|
|
456
|
+
const statusLine = (statuses) => `2xx ${statuses['2xx']} 304 ${statuses['304']} 3xx ${statuses.other3xx} 404 ${statuses['404']} 410 ${statuses['410']} 4xx ${statuses.other4xx} 429 ${statuses['429']} 5xx ${statuses['5xx']}`;
|
|
457
|
+
const first = data.days[0]?.day;
|
|
458
|
+
const last = data.days.at(-1)?.day;
|
|
459
|
+
return [
|
|
460
|
+
...access,
|
|
461
|
+
`Bot Traffic, ${crawler}${first && last ? `, ${first} to ${last}` : ''}`,
|
|
462
|
+
fields([
|
|
463
|
+
['Collected', `${data.collection.fromDay} to ${data.collection.toDay}`],
|
|
464
|
+
['Complete through', data.collection.completeThroughDay ?? ''],
|
|
465
|
+
['Requests', totals.requests],
|
|
466
|
+
['Statuses', statusLine(totals.statuses)],
|
|
467
|
+
['Content', `html ${totals.contents.html} js ${totals.contents.js} css ${totals.contents.css} image ${totals.contents.image} other ${totals.contents.other}`],
|
|
468
|
+
['Wasted share', percent(totals.wastedShare)],
|
|
469
|
+
['Cache hit share', percent(totals.cacheHitShare)],
|
|
470
|
+
['Origin avg', totals.originAvgMs === null ? '' : `${totals.originAvgMs} ms`],
|
|
471
|
+
]),
|
|
472
|
+
data.days.length === 0 ? 'No collected days in this window.' : 'Days',
|
|
473
|
+
...data.days.map(day => ` ${day.day}${day.complete ? '' : ' (partial)'} ${day.requests} requests ${statusLine(day.statuses)}`),
|
|
474
|
+
data.errorPaths.length === 0 ? '' : 'Error paths',
|
|
475
|
+
...data.errorPaths.map(path => ` ${path.status} ${path.requests} ${path.path} last ${path.lastDay}`),
|
|
476
|
+
].filter(Boolean).join('\n');
|
|
477
|
+
}
|
|
436
478
|
export function renderAnalytics(view, data) {
|
|
437
479
|
const delta = (label, value) => [
|
|
438
480
|
label,
|
|
@@ -979,7 +1021,9 @@ export function renderMonitoredPages(data) {
|
|
|
979
1021
|
return 'No monitored Pages. Start one with `nuxtseo page scan <url>`.';
|
|
980
1022
|
return [
|
|
981
1023
|
`Monitored Pages (${data.pages.length})`,
|
|
982
|
-
...data.pages.map(page =>
|
|
1024
|
+
...data.pages.map(page => page.pauseReason
|
|
1025
|
+
? ` paused ${page.path} ${page.pauseReason} last scan ${page.lastScanAt ?? 'never'}`
|
|
1026
|
+
: ` ${page.enabled ? 'on ' : 'off '} ${page.path} last scan ${page.lastScanAt ?? 'never'}`),
|
|
983
1027
|
].join('\n');
|
|
984
1028
|
}
|
|
985
1029
|
export function renderScanDetail(data) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuxtseo/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.11",
|
|
5
5
|
"description": "Command line interface for the Nuxt SEO public API.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://nuxtseo.com/pro",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@clack/prompts": "^1.8.0",
|
|
36
|
-
"@nuxtseo/protocol": "^0.5.
|
|
37
|
-
"@nuxtseo/sdk": "^0.5.
|
|
36
|
+
"@nuxtseo/protocol": "^0.5.11",
|
|
37
|
+
"@nuxtseo/sdk": "^0.5.11",
|
|
38
38
|
"citty": "^0.2.2",
|
|
39
39
|
"pathe": "^2.0.3"
|
|
40
40
|
},
|
|
@@ -51,8 +51,16 @@ Read the matching file before you act on its subject:
|
|
|
51
51
|
instead.
|
|
52
52
|
|
|
53
53
|
3. **Token.** Run `nuxtseo whoami --json`. It returns the Team, role, scopes,
|
|
54
|
-
and token expiry. Exit `3` means no working token.
|
|
55
|
-
|
|
54
|
+
and token expiry. Exit `3` means no working token.
|
|
55
|
+
If authentication is missing, invalid, or expired, run `nuxtseo login --no-browser`.
|
|
56
|
+
A missing referenced keychain credential can instead exit `7` with `state_error`; use the same login flow.
|
|
57
|
+
If browser automation is authorized, open the printed URL in the intended signed-in account.
|
|
58
|
+
Verify the account, Team, machine, and matching pairing code before approving.
|
|
59
|
+
Select the least access needed. Editor supports Scans and Action claims.
|
|
60
|
+
Keep the login process running until it saves the credential, then repeat `whoami --json`.
|
|
61
|
+
Honor browser connection approval. Never copy cookies or bypass sign-in.
|
|
62
|
+
If browser access or approval is unavailable, ask the user to approve the printed URL.
|
|
63
|
+
If login reports a transport failure, investigate it before starting another pairing.
|
|
56
64
|
The other route is a token from
|
|
57
65
|
<https://nuxtseo.com/pro/dashboard/settings/api-tokens>, exported as
|
|
58
66
|
`NUXTSEO_TOKEN`. Never put a token in an argument, a file, or a commit.
|
|
@@ -246,6 +254,7 @@ you got:
|
|
|
246
254
|
| `page issues` | `availableKeys` |
|
|
247
255
|
| `search cohorts` | `analysed: false`: no completed crawl, no Google index state, or `reason: "sampled-index-state"` |
|
|
248
256
|
| `vitals summary` | `available: false` |
|
|
257
|
+
| `bot-traffic` | `collection: null`; `access._tag` other than `collecting` |
|
|
249
258
|
| `research keywords`, `research rankings`, `research domain-*`, `page issues`, `search cohorts`, `vitals findings` | `data.message`, and `data.tip` for the repair |
|
|
250
259
|
|
|
251
260
|
Read `data.message` before the list. For example, `research keywords` refuses
|
|
@@ -283,6 +292,9 @@ Do not compare this population with a summary or cohort from another capture.
|
|
|
283
292
|
is normal.
|
|
284
293
|
- `status` is the verdict, `performance` the lab score, `vitals` what real
|
|
285
294
|
users measured. Never substitute one for another.
|
|
295
|
+
- `bot-traffic --crawler googlebot` or `--crawler bingbot` counts verified search engine requests at the Site's Cloudflare edge. It is
|
|
296
|
+
not Search Console's Crawl Stats report, so its totals can differ. A high
|
|
297
|
+
`wastedShare` during a planned URL retirement is expected.
|
|
286
298
|
- `page inspect` reads the Nuxt SEO observation store. `search inspect` reads
|
|
287
299
|
the latest retained Google URL Inspection for the same URL.
|
|
288
300
|
`search inspect <url> --fresh --yes` requests Google URL Inspection through
|
|
@@ -62,6 +62,7 @@ a research unit.
|
|
|
62
62
|
| Which route family is Google declining | `search cohorts` |
|
|
63
63
|
| Why is this one URL not indexed | `search inspect <url>` |
|
|
64
64
|
| When did this URL change index state | `search index-history`, with `--url` |
|
|
65
|
+
| Which URLs answer search engines with errors | `bot-traffic` with the Googlebot or Bingbot crawler filter |
|
|
65
66
|
| Which pages earn the clicks | `search analytics pages` |
|
|
66
67
|
| Which terms is the Site visible for | `search analytics keywords` |
|
|
67
68
|
| Which pages are losing clicks | `audit content-decay` |
|
|
@@ -108,7 +109,7 @@ lines.
|
|
|
108
109
|
| --- | --- |
|
|
109
110
|
| `whoami` | Credential, Team, role, granted scopes, token expiry. The cheapest health check. Reads no Site |
|
|
110
111
|
| `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 |
|
|
111
|
-
| `login` | Pairs the CLI with a Team through the browser.
|
|
112
|
+
| `login` | Pairs the CLI with a Team through the browser. An authorized agent can run `--no-browser` and approve through the intended signed-in account. Verify the account, Team, machine, and matching code first. If approval is unavailable, ask the user to approve the printed URL. `--with-token` reads a token from a hidden prompt or stdin. `--no-browser` skips opening the browser |
|
|
112
113
|
| `logout` | Discards the stored credential. Returns a `CliLogout` value |
|
|
113
114
|
| `sites list` | Every accessible Site. The source of Site IDs |
|
|
114
115
|
| `sites use <site-id>` | Persists a default Site in local config, for the human, not for you |
|
|
@@ -142,6 +143,12 @@ lines.
|
|
|
142
143
|
`failureKind` says why a Scan failed, for example `timeout`, `rejected`, or `quota`.
|
|
143
144
|
It is null on a Scan that did not fail, and on a Scan that failed before kinds were recorded.
|
|
144
145
|
|
|
146
|
+
Reuse saved successful Scan details. Read only the details needed for the missing proof.
|
|
147
|
+
For persistent Poor metrics, start with the latest two completed Scans per canonical Page and strategy.
|
|
148
|
+
Read older details only when the comparison needs them. Missing details mean incomplete coverage, never healthy performance.
|
|
149
|
+
If the server reports a retry delay, respect it across the work queue.
|
|
150
|
+
If throttling repeats, stop parallel reads and preserve the failures for a later paced retry.
|
|
151
|
+
|
|
145
152
|
`comparison` has one of three tags.
|
|
146
153
|
`compared` lists each metric both Scans measured, with `previous`, `current`, `delta`, and `severity`.
|
|
147
154
|
`incompatible` names why the two Scans differ, for example `lighthouse-version`. Do not compare their numbers.
|
|
@@ -263,6 +270,7 @@ A missing query row is never evidence of no demand.
|
|
|
263
270
|
|
|
264
271
|
| Command | What it returns, and its flags |
|
|
265
272
|
| --- | --- |
|
|
273
|
+
| `bot-traffic` | Bot Traffic counts verified Googlebot or Bingbot requests per UTC day at the Site's Cloudflare zone. `--crawler googlebot\|bingbot` defaults to Googlebot. Statuses split into `2xx`, `304`, `other3xx`, `404`, `410`, `other4xx`, `429`, `5xx`; content into `html`, `js`, `css`, `image`, `other`. `totals.wastedShare` counts every answer except 2xx and 304. `errorPaths` lists the most requested 4xx, 429 and 5xx paths, without 410. `--days 1..90` (default 28), today included. `days` lists only collected days, and a `complete: false` day is partial. `collection: null` means no collection ran yet. Read `access` first: `zone_access_missing` lists the Cloudflare permissions (`Zone: Read`, `Analytics: Read`) and OAuth scopes to grant. `collection_failed` names the reason. Stored days stop at the last collection. A Site without a Cloudflare zone returns `conflict`. These edge counts can differ from Search Console's Crawl Stats report. Source: `packages/protocol/src/v1/analytics.ts`, `packages/cli/src/commands.ts` |
|
|
266
274
|
| `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 |
|
|
267
275
|
|
|
268
276
|
## Research, backlinks, and mentions
|
|
@@ -332,9 +340,9 @@ already answer.
|
|
|
332
340
|
|
|
333
341
|
### Claim response
|
|
334
342
|
|
|
335
|
-
`actions resolve` saves your Claim. It returns before
|
|
343
|
+
`actions resolve` saves your Claim. It returns before verification completes.
|
|
336
344
|
`status: "open"` stays unchanged until the engine verifies the Action.
|
|
337
|
-
Human output shows `Claimed, verifying
|
|
345
|
+
Human output shows `Claimed, verifying`.
|
|
338
346
|
Claimed Actions leave `actions list`. Use `actions show <action-id>` to check them.
|
|
339
347
|
|
|
340
348
|
Both `resolve` and `show` return these additive fields:
|
|
@@ -342,8 +350,12 @@ Both `resolve` and `show` return these additive fields:
|
|
|
342
350
|
| Field | Meaning |
|
|
343
351
|
| --- | --- |
|
|
344
352
|
| `markedAt` | ISO timestamp when your Claim was saved, or `null` before a Claim. |
|
|
345
|
-
| `checkBackAt` |
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
`scan-queued`
|
|
353
|
+
| `checkBackAt` | Supported ISO timestamp to check again, or `null` when the schedule is unknown. |
|
|
354
|
+
|
|
355
|
+
`recheck-queued` requests a fresh check of the cited URLs.
|
|
356
|
+
`scan-queued` means a source refresh is queued or already running.
|
|
357
|
+
`next-assessment` waits for a site check, which can reuse stored results.
|
|
358
|
+
An assessment can already be queued without requesting fresh Crawl collection.
|
|
359
|
+
Unknown check times stay null, including retries and later reads.
|
|
360
|
+
A supported check-back time does not promise completed verification.
|
|
349
361
|
A self-resolved Claim returns `status: "verified"` and `verification: "user-resolved"`.
|
|
@@ -18,6 +18,22 @@ 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
|
+
## Provisional Site verdicts
|
|
22
|
+
|
|
23
|
+
If `status` returns degraded data quality, read `dataQuality.reason` with `unavailableProofs`.
|
|
24
|
+
The reason records the unavailable stage. It does not identify the underlying database or network fault.
|
|
25
|
+
|
|
26
|
+
| Reason | Recorded outcome |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| `completed-crawl-unavailable` | The loader found no completed Crawl evidence with a completion clock. |
|
|
29
|
+
| `crawl-read-failed` | The collection read failed. |
|
|
30
|
+
| `crawl-snapshot-unavailable` | Generation could not reread Findings for the pinned Crawl. |
|
|
31
|
+
| `crawl-snapshot-read-failed` | The pinned Findings read failed. |
|
|
32
|
+
|
|
33
|
+
A null reason can mean an older assessment or another missing proof.
|
|
34
|
+
It never clears the missing proof or proves zero blockers.
|
|
35
|
+
A completed Crawl elsewhere does not identify which stage failed for this assessment.
|
|
36
|
+
|
|
21
37
|
## A soft failure looks like an empty result
|
|
22
38
|
|
|
23
39
|
Some commands refuse the argument and still exit `0` with an empty list. The
|
|
@@ -138,6 +154,7 @@ command returns; never guess a chain. Verified against the response schemas.
|
|
|
138
154
|
| `sitemaps submission` | no list; `data.state` | none |
|
|
139
155
|
| `sitemaps inspect` | no list; `data.capture`, `data.state` | none |
|
|
140
156
|
| `search watches` | `data.watched`; each item's `checkpoints` | none |
|
|
157
|
+
| `bot-traffic` | `data.days` and `data.errorPaths` | none |
|
|
141
158
|
| `sitemaps urls` | `data.items` | `data.page.nextCursor`, `data.page.limit` |
|
|
142
159
|
| `audit content-decay` | `data.rows` | `data.page`; `data.total`, `data.truncated` |
|
|
143
160
|
| `audit link-opportunities` | `data.rows` | `data.page`; `data.total` |
|
|
@@ -167,7 +184,7 @@ Branch on the exit code, not message text.
|
|
|
167
184
|
| ---: | --- | --- |
|
|
168
185
|
| `0` | Success, including a closed stdout pipe | Continue |
|
|
169
186
|
| `2` | Invalid input, or mutation without `--yes` | Fix arguments. Do not retry unchanged |
|
|
170
|
-
| `3` | Missing, invalid, or expired authentication |
|
|
187
|
+
| `3` | Missing, invalid, or expired authentication | Run `nuxtseo login --no-browser`. Follow Setup's authorized browser pairing flow, then repeat `whoami --json` |
|
|
171
188
|
| `4` | Forbidden, scope, or entitlement failure | Report the plan or token blocker |
|
|
172
189
|
| `5` | Conflict, stale evidence, or ambiguous Site | Re-read. Pass `--site` if ambiguous |
|
|
173
190
|
| `6` | Rate limit, `quota_exhausted`, provider outage, or timeout | Read retry metadata, then wait |
|
|
@@ -182,5 +199,10 @@ may also include the retry delay, the rate policy, the requests remaining, the
|
|
|
182
199
|
rate limit, the window, the reset delay, and structured details. Keep the
|
|
183
200
|
request ID when reporting a problem.
|
|
184
201
|
|
|
202
|
+
If its retry wait reaches the request deadline, the CLI preserves the last verified API failure.
|
|
203
|
+
That preserves the server code, request ID, and retry metadata.
|
|
204
|
+
Respect the reported retry delay before starting more calls.
|
|
205
|
+
Network-only timeouts still return `request_timeout`. Explicit cancellation returns exit `130`.
|
|
206
|
+
|
|
185
207
|
Only exit `6` means the same command may work later. The SDK already retried
|
|
186
208
|
HTTP 429 responses. Mutations are never retried automatically.
|