@nuxtseo/cli 0.1.2 → 0.1.3
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 +3 -0
- package/dist/cli.js +4 -1
- package/dist/commands.js +48 -1
- package/dist/render.d.ts +2 -1
- package/dist/render.js +28 -0
- package/package.json +3 -3
- package/skills/nuxtseo-cli/SKILL.md +2 -0
package/README.md
CHANGED
|
@@ -172,6 +172,7 @@ nuxtseo page scan <url>
|
|
|
172
172
|
nuxtseo performance
|
|
173
173
|
nuxtseo search status
|
|
174
174
|
nuxtseo search analytics <pages|keywords>
|
|
175
|
+
nuxtseo search indexing <summary|urls>
|
|
175
176
|
nuxtseo research overview
|
|
176
177
|
nuxtseo research keywords <topic>
|
|
177
178
|
nuxtseo research serp <keyword>
|
|
@@ -189,6 +190,7 @@ performance, research, content, and account setup. The menu prints the direct
|
|
|
189
190
|
command it runs.
|
|
190
191
|
|
|
191
192
|
`search status` reads stored connection state. It never waits for Google.
|
|
193
|
+
`search indexing summary` reads retained URL Inspection coverage.
|
|
192
194
|
`research keywords`, `research serp`, and `research rankings` can use the Team
|
|
193
195
|
research allowance. Keyword responses report cache use in `evidence`. SERP and
|
|
194
196
|
ranking responses report `cached: true`. Cached responses use no unit.
|
|
@@ -204,6 +206,7 @@ responses.
|
|
|
204
206
|
| `backlinks recoverable` | `--limit 1..200`, `--offset >=0` | `--limit 100 --offset 0` |
|
|
205
207
|
| `mentions list` | `--limit 1..200` | `--limit 100` |
|
|
206
208
|
| `search analytics` | `--limit 1..100`, `--page >=1` | `--limit 25 --page 1` |
|
|
209
|
+
| `search indexing` | `--limit 1..500`, `--offset >=0` | `--limit 50 --offset 0` |
|
|
207
210
|
| `content briefs list` | `--limit 1..100`, `--offset >=0` | `--limit 25 --offset 0` |
|
|
208
211
|
|
|
209
212
|
Keep the server order for actions. For another page, pass the next offset or
|
package/dist/cli.js
CHANGED
|
@@ -252,6 +252,7 @@ async function interactiveBare(runtime, globals) {
|
|
|
252
252
|
options: [
|
|
253
253
|
{ value: 'performance', label: 'Performance overview' },
|
|
254
254
|
{ value: 'connection', label: 'Search Console connection' },
|
|
255
|
+
{ value: 'indexing', label: 'Search indexing coverage' },
|
|
255
256
|
{ value: 'pages', label: 'Search Console Pages' },
|
|
256
257
|
{ value: 'keywords', label: 'Search Console queries' },
|
|
257
258
|
],
|
|
@@ -265,7 +266,9 @@ async function interactiveBare(runtime, globals) {
|
|
|
265
266
|
? ['performance']
|
|
266
267
|
: task === 'connection'
|
|
267
268
|
? ['search', 'status']
|
|
268
|
-
:
|
|
269
|
+
: task === 'indexing'
|
|
270
|
+
? ['search', 'indexing', 'summary']
|
|
271
|
+
: ['search', 'analytics', task];
|
|
269
272
|
return runInteractiveCommand(command, runtime, globals);
|
|
270
273
|
}
|
|
271
274
|
if (group === 'research') {
|
package/dist/commands.js
CHANGED
|
@@ -5,7 +5,7 @@ import { openBrowser } from './browser.js';
|
|
|
5
5
|
import { EXIT_CODE, fail, fromSdkFailure, ok } from './failures.js';
|
|
6
6
|
import { awaitPairingApproval, createCliPairingClient, startPairing } from './pairing.js';
|
|
7
7
|
import { parseAbsolutePageUrl, parseChoice, parseInteger } from './parse.js';
|
|
8
|
-
import { renderAction, renderActionResolution, renderActions, renderContentBrief, renderContentBriefCreated, renderContentBriefs, renderContentDecay, renderDuplicateClusters, renderKeywordResearch, renderLinkOpportunities, renderMentions, renderPageInspection, renderPageScan, renderPerformance, renderRankingsResearch, renderRecoverableBacklinks, renderResearchOverview, renderSearchAnalytics, renderSearchStatus, renderSerpResearch, renderSites, renderUsage, } from './render.js';
|
|
8
|
+
import { renderAction, renderActionResolution, renderActions, renderContentBrief, renderContentBriefCreated, renderContentBriefs, renderContentDecay, renderDuplicateClusters, renderIndexingDiagnostics, renderKeywordResearch, renderLinkOpportunities, renderMentions, renderPageInspection, renderPageScan, renderPerformance, renderRankingsResearch, renderRecoverableBacklinks, renderResearchOverview, renderSearchAnalytics, renderSearchStatus, renderSerpResearch, renderSites, renderUsage, } from './render.js';
|
|
9
9
|
import { writeCliResponse, writeDiagnostic, writeOutput, writeProtocolResponse } from './runtime.js';
|
|
10
10
|
import { resolveSite } from './site.js';
|
|
11
11
|
import { clearCredential, getCredentialStatus, readConfig, resolveApiUrl, saveCredential, updateConfig, } from './state/index.js';
|
|
@@ -447,6 +447,36 @@ async function searchAnalytics(runtime, globals, args) {
|
|
|
447
447
|
}, { signal: runtime.requestSignal }));
|
|
448
448
|
return present(runtime, globals, response, value => renderSearchAnalytics(value.data));
|
|
449
449
|
}
|
|
450
|
+
async function searchIndexing(runtime, globals, args) {
|
|
451
|
+
const view = parseChoice(args.view, { name: 'view', choices: ['summary', 'urls'] });
|
|
452
|
+
if (view._tag === 'Err')
|
|
453
|
+
return view;
|
|
454
|
+
const status = args.status === undefined
|
|
455
|
+
? ok(undefined)
|
|
456
|
+
: parseChoice(args.status, { name: '--status', choices: ['indexed', 'not_indexed', 'pending'] });
|
|
457
|
+
if (status._tag === 'Err')
|
|
458
|
+
return status;
|
|
459
|
+
const limit = parseInteger(args.limit, { name: '--limit', minimum: 1, maximum: 500, defaultValue: 50 });
|
|
460
|
+
if (limit._tag === 'Err')
|
|
461
|
+
return limit;
|
|
462
|
+
const offset = parseInteger(args.offset, { name: '--offset', minimum: 0, defaultValue: 0 });
|
|
463
|
+
if (offset._tag === 'Err')
|
|
464
|
+
return offset;
|
|
465
|
+
const resolved = await apiAndSite(runtime, globals);
|
|
466
|
+
if (resolved._tag === 'Err')
|
|
467
|
+
return resolved;
|
|
468
|
+
const response = await withSpinner(runtime, 'Loading Search Console indexing', () => resolved.value.api.client.search.readIndexingDiagnostics({
|
|
469
|
+
params: { siteId: resolved.value.siteId },
|
|
470
|
+
query: {
|
|
471
|
+
view: view.value,
|
|
472
|
+
issue: args.issue,
|
|
473
|
+
status: status.value,
|
|
474
|
+
limit: limit.value,
|
|
475
|
+
offset: offset.value,
|
|
476
|
+
},
|
|
477
|
+
}, { signal: runtime.requestSignal }));
|
|
478
|
+
return present(runtime, globals, response, value => renderIndexingDiagnostics(value.data));
|
|
479
|
+
}
|
|
450
480
|
async function researchOverview(runtime, globals) {
|
|
451
481
|
const resolved = await apiAndSite(runtime, globals);
|
|
452
482
|
if (resolved._tag === 'Err')
|
|
@@ -928,6 +958,23 @@ export function createRootCommand(runtime, globals, execution) {
|
|
|
928
958
|
sortDir: args['sort-dir'],
|
|
929
959
|
}), args._, 1)(),
|
|
930
960
|
}),
|
|
961
|
+
indexing: defineCommand({
|
|
962
|
+
meta: { name: 'indexing', description: 'Read retained Search Console indexing coverage' },
|
|
963
|
+
args: {
|
|
964
|
+
view: positional('summary-or-urls', 'summary or urls'),
|
|
965
|
+
issue: { type: 'string', description: 'Filter URLs by issue type' },
|
|
966
|
+
status: { type: 'enum', options: ['indexed', 'not_indexed', 'pending'], description: 'Filter URLs by indexing status' },
|
|
967
|
+
limit: { type: 'string', description: 'Maximum URLs, 1 to 500' },
|
|
968
|
+
offset: { type: 'string', description: 'Pagination offset' },
|
|
969
|
+
},
|
|
970
|
+
run: ({ args }) => capture(execution, () => searchIndexing(runtime, globals, {
|
|
971
|
+
view: args.view,
|
|
972
|
+
issue: args.issue,
|
|
973
|
+
status: args.status,
|
|
974
|
+
limit: args.limit,
|
|
975
|
+
offset: args.offset,
|
|
976
|
+
}), args._, 1)(),
|
|
977
|
+
}),
|
|
931
978
|
},
|
|
932
979
|
});
|
|
933
980
|
return defineCommand({
|
package/dist/render.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { ActionList, ActionResolve, ActionShow } from '@nuxtseo/protocol/v1
|
|
|
3
3
|
import type { AuditContentDecay, AuditDuplicateClusters, AuditLinkOpportunities } from '@nuxtseo/protocol/v1/audit';
|
|
4
4
|
import type { Mentions, RecoverableBacklinks } from '@nuxtseo/protocol/v1/backlinks';
|
|
5
5
|
import type { ContentBrief, ContentBriefCreateData, ContentBriefListData } from '@nuxtseo/protocol/v1/content';
|
|
6
|
-
import type { SearchAnalyticsData, SearchStatusData } from '@nuxtseo/protocol/v1/gsc';
|
|
6
|
+
import type { IndexingDiagnosticsData, SearchAnalyticsData, SearchStatusData } from '@nuxtseo/protocol/v1/gsc';
|
|
7
7
|
import type { PageInspect, PageScan } from '@nuxtseo/protocol/v1/pages';
|
|
8
8
|
import type { SitePerformanceOverview } from '@nuxtseo/protocol/v1/performance';
|
|
9
9
|
import type { KeywordResearchData, RankingsResearchData, SerpResearchData, StoredResearchOverview } from '@nuxtseo/protocol/v1/research';
|
|
@@ -17,6 +17,7 @@ export declare function renderPageScan(data: PageScan): string;
|
|
|
17
17
|
export declare function renderPerformance(data: SitePerformanceOverview): string;
|
|
18
18
|
export declare function renderSearchStatus(data: SearchStatusData): string;
|
|
19
19
|
export declare function renderSearchAnalytics(data: SearchAnalyticsData): string;
|
|
20
|
+
export declare function renderIndexingDiagnostics(data: IndexingDiagnosticsData): string;
|
|
20
21
|
export declare function renderResearchOverview(data: StoredResearchOverview): string;
|
|
21
22
|
export declare function renderKeywordResearch(data: KeywordResearchData): string;
|
|
22
23
|
export declare function renderSerpResearch(data: SerpResearchData): string;
|
package/dist/render.js
CHANGED
|
@@ -151,6 +151,34 @@ export function renderSearchAnalytics(data) {
|
|
|
151
151
|
['Rows', 'rows' in data ? data.rows.length : data.type === 'timeseries' ? data.daily.length : 0],
|
|
152
152
|
]);
|
|
153
153
|
}
|
|
154
|
+
export function renderIndexingDiagnostics(data) {
|
|
155
|
+
if (data.view === 'summary') {
|
|
156
|
+
const indexedPercent = data.totalUrls > 0
|
|
157
|
+
? `${(data.indexed / data.totalUrls * 100).toFixed(1)}%`
|
|
158
|
+
: '0.0%';
|
|
159
|
+
const issues = data.issues
|
|
160
|
+
.filter(issue => issue.count > 0)
|
|
161
|
+
.sort((left, right) => right.count - left.count)
|
|
162
|
+
.map(issue => `${issue.count} ${issue.label} ${issue.severity}`);
|
|
163
|
+
return [
|
|
164
|
+
fields([
|
|
165
|
+
['Known URLs', data.totalUrls],
|
|
166
|
+
['Indexed', data.indexed],
|
|
167
|
+
['Not indexed', Math.max(0, data.totalUrls - data.indexed)],
|
|
168
|
+
['Indexed rate', indexedPercent],
|
|
169
|
+
['As of', data.asOf],
|
|
170
|
+
]),
|
|
171
|
+
...(issues.length > 0 ? ['Issues', ...issues] : []),
|
|
172
|
+
].join('\n');
|
|
173
|
+
}
|
|
174
|
+
if (data.urls.length === 0)
|
|
175
|
+
return 'No Search Console indexing URLs match these filters.';
|
|
176
|
+
return [
|
|
177
|
+
`Search Console indexing URLs (${data.urls.length} of ${data.total})`,
|
|
178
|
+
...data.urls.map(row => `${row.verdict ?? 'unknown'} ${row.coverageState ?? 'unknown'}\n ${row.url}`),
|
|
179
|
+
data.hasMore ? `More URLs available after offset ${data.offset + data.limit}.` : '',
|
|
180
|
+
].filter(Boolean).join('\n');
|
|
181
|
+
}
|
|
154
182
|
export function renderResearchOverview(data) {
|
|
155
183
|
const subject = data.subject
|
|
156
184
|
? fields([
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuxtseo/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.3",
|
|
5
5
|
"description": "Command line interface for the NuxtSEO public API.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://nuxtseo.com/pro",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@clack/prompts": "^1.7.0",
|
|
35
35
|
"citty": "^0.2.2",
|
|
36
36
|
"pathe": "^2.0.3",
|
|
37
|
-
"@nuxtseo/sdk": "^0.1.
|
|
37
|
+
"@nuxtseo/sdk": "^0.1.3"
|
|
38
38
|
},
|
|
39
39
|
"optionalDependencies": {
|
|
40
40
|
"@napi-rs/keyring": "^1.3.0"
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@types/node": "^26.2.0",
|
|
45
45
|
"publint": "^0.3.24",
|
|
46
46
|
"typescript": "npm:typescript-native-bridge@6.0.3-bridge.10.tsgo.7.0.2",
|
|
47
|
-
"@nuxtseo/protocol": "0.1.
|
|
47
|
+
"@nuxtseo/protocol": "0.1.3"
|
|
48
48
|
},
|
|
49
49
|
"publishConfig": {
|
|
50
50
|
"access": "public"
|
|
@@ -26,6 +26,7 @@ report `cached`.
|
|
|
26
26
|
|
|
27
27
|
`search status` reads stored connection state. It never waits for Google.
|
|
28
28
|
`search analytics` reads Search Console rows through the public API.
|
|
29
|
+
`search indexing` reads retained URL Inspection coverage through the public API.
|
|
29
30
|
|
|
30
31
|
## Get the binary
|
|
31
32
|
|
|
@@ -115,6 +116,7 @@ handling failures, read [CLI protocol](references/protocol.md).
|
|
|
115
116
|
| `performance` | Site performance overview | Medians for perf, a11y, SEO, LCP, TBT, CLS |
|
|
116
117
|
| `search status` | Stored Search Console connection | Provider free |
|
|
117
118
|
| `search analytics <pages\|keywords>` | Search Console Page or query rows | `--period`, `--limit`, `--page`, `--search` |
|
|
119
|
+
| `search indexing <summary\|urls>` | Retained URL Inspection coverage | `summary` returns indexed counts; `urls` supports `--issue`, `--status`, `--limit`, `--offset` |
|
|
118
120
|
| `research overview` | Stored Site and competitor research | Metrics, history, gaps, and quick wins |
|
|
119
121
|
| `research keywords <topic>` | Live keyword ideas | Volume, difficulty, intent, and cost data |
|
|
120
122
|
| `research serp <keyword>` | Live SERP snapshot | Results, features, and fetch time |
|