@nuxtseo/cli 0.1.3 → 0.1.4
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 +8 -6
- package/dist/command-contract.d.ts +2 -1
- package/dist/command-contract.js +4 -2
- package/dist/commands.js +49 -1
- package/dist/render.d.ts +2 -0
- package/dist/render.js +12 -0
- package/package.json +3 -3
- package/skills/nuxtseo-cli/SKILL.md +5 -5
- package/skills/nuxtseo-cli/references/protocol.md +2 -1
package/README.md
CHANGED
|
@@ -123,12 +123,14 @@ to stdout and writes the readable recovery message to stderr.
|
|
|
123
123
|
|
|
124
124
|
Local outcomes have no server protocol body. With `--json`, commands such as
|
|
125
125
|
bare `nuxtseo`, `config`, `logout`, and `sites use` emit a tagged CLI-owned JSON
|
|
126
|
-
value with `schemaVersion: 1`.
|
|
127
|
-
and exit code. These tags are separate from
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
value with `schemaVersion: 1`. `CliHelp` uses `schemaVersion: 2`. Local failures
|
|
127
|
+
emit `CliError` with a stable code and exit code. These tags are separate from
|
|
128
|
+
protocol envelopes.
|
|
129
|
+
|
|
130
|
+
`--help --json` returns the selected command, inherited `globalOptions`,
|
|
131
|
+
positional `arguments`, command-specific `localOptions`, and `subcommands` as
|
|
132
|
+
`CliHelp`. Option names are strict. An unknown option exits `2` before
|
|
133
|
+
authentication or network work.
|
|
132
134
|
|
|
133
135
|
## Automation controls
|
|
134
136
|
|
|
@@ -16,12 +16,13 @@ export interface CliHelpArgument {
|
|
|
16
16
|
}
|
|
17
17
|
export interface CliHelpResponse {
|
|
18
18
|
_tag: 'CliHelp';
|
|
19
|
-
schemaVersion:
|
|
19
|
+
schemaVersion: 2;
|
|
20
20
|
cliVersion: string;
|
|
21
21
|
command: string;
|
|
22
22
|
description?: string;
|
|
23
23
|
globalOptions: CliHelpArgument[];
|
|
24
24
|
arguments: CliHelpArgument[];
|
|
25
|
+
localOptions: CliHelpArgument[];
|
|
25
26
|
subcommands: Array<{
|
|
26
27
|
name: string;
|
|
27
28
|
description?: string;
|
package/dist/command-contract.js
CHANGED
|
@@ -54,14 +54,16 @@ function argumentsFor(command) {
|
|
|
54
54
|
export function describeCommand(root, rawArgs, cliVersion) {
|
|
55
55
|
const resolved = resolveCommand(root, rawArgs.filter(argument => argument !== '--help' && argument !== '-h'));
|
|
56
56
|
const meta = commandMeta(resolved.command);
|
|
57
|
+
const localArguments = resolved.command === root ? [] : argumentsFor(resolved.command);
|
|
57
58
|
return {
|
|
58
59
|
_tag: 'CliHelp',
|
|
59
|
-
schemaVersion:
|
|
60
|
+
schemaVersion: 2,
|
|
60
61
|
cliVersion,
|
|
61
62
|
command: resolved.path.join(' '),
|
|
62
63
|
...(meta.description === undefined ? {} : { description: meta.description }),
|
|
63
64
|
globalOptions: argumentsFor(root).filter(argument => argument.type !== 'positional'),
|
|
64
|
-
arguments:
|
|
65
|
+
arguments: localArguments.filter(argument => argument.type === 'positional'),
|
|
66
|
+
localOptions: localArguments.filter(argument => argument.type !== 'positional'),
|
|
65
67
|
subcommands: Object.entries(commandChildren(resolved.command)).flatMap(([name, value]) => {
|
|
66
68
|
const child = childCommand(value);
|
|
67
69
|
if (!child)
|
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, renderIndexingDiagnostics, 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, renderTimeline, 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';
|
|
@@ -606,6 +606,27 @@ async function auditLinkOpportunities(runtime, globals) {
|
|
|
606
606
|
}, { signal: runtime.requestSignal }));
|
|
607
607
|
return present(runtime, globals, response, value => renderLinkOpportunities(value.data));
|
|
608
608
|
}
|
|
609
|
+
async function timelineEntries(runtime, globals, args) {
|
|
610
|
+
const limit = parseInteger(args.limit, { name: '--limit', minimum: 1, maximum: 100, defaultValue: 25 });
|
|
611
|
+
if (limit._tag === 'Err')
|
|
612
|
+
return limit;
|
|
613
|
+
const resolved = await apiAndSite(runtime, globals);
|
|
614
|
+
if (resolved._tag === 'Err')
|
|
615
|
+
return resolved;
|
|
616
|
+
const response = await withSpinner(runtime, 'Loading Timeline', () => resolved.value.api.client.timeline.entries({
|
|
617
|
+
params: { siteId: resolved.value.siteId },
|
|
618
|
+
query: {
|
|
619
|
+
kinds: args.kind,
|
|
620
|
+
feature: args.feature,
|
|
621
|
+
severity: args.severity,
|
|
622
|
+
since: args.since,
|
|
623
|
+
limit: limit.value,
|
|
624
|
+
cursor: args.cursor,
|
|
625
|
+
includeClosed: args.includeClosed,
|
|
626
|
+
},
|
|
627
|
+
}, { signal: runtime.requestSignal }));
|
|
628
|
+
return present(runtime, globals, response, value => renderTimeline(value.data));
|
|
629
|
+
}
|
|
609
630
|
async function contentBriefList(runtime, globals, args) {
|
|
610
631
|
const status = args.status === undefined
|
|
611
632
|
? ok(undefined)
|
|
@@ -977,6 +998,32 @@ export function createRootCommand(runtime, globals, execution) {
|
|
|
977
998
|
}),
|
|
978
999
|
},
|
|
979
1000
|
});
|
|
1001
|
+
const timeline = defineCommand({
|
|
1002
|
+
meta: { name: 'timeline', description: 'Read the Timeline — what changed on the Site' },
|
|
1003
|
+
subCommands: {
|
|
1004
|
+
list: defineCommand({
|
|
1005
|
+
meta: { name: 'list', description: 'List Timeline Entries' },
|
|
1006
|
+
args: {
|
|
1007
|
+
'kind': { type: 'string', description: 'Comma-separated Timeline Entry kinds, e.g. traffic.dropped,indexing.changed' },
|
|
1008
|
+
'feature': { type: 'string', description: 'Filter to the kinds registered under this feature' },
|
|
1009
|
+
'severity': { type: 'string', description: 'Comma-separated severities: info, notable, high' },
|
|
1010
|
+
'since': { type: 'string', description: 'Only entries at or after this ISO timestamp' },
|
|
1011
|
+
'limit': { type: 'string', description: 'Maximum Timeline Entries, 1 to 100' },
|
|
1012
|
+
'cursor': { type: 'string', description: 'Opaque pagination cursor from a previous page' },
|
|
1013
|
+
'include-closed': { type: 'boolean', description: 'Include closed episodes' },
|
|
1014
|
+
},
|
|
1015
|
+
run: ({ args }) => capture(execution, () => timelineEntries(runtime, globals, {
|
|
1016
|
+
kind: args.kind,
|
|
1017
|
+
feature: args.feature,
|
|
1018
|
+
severity: args.severity,
|
|
1019
|
+
since: args.since,
|
|
1020
|
+
limit: args.limit,
|
|
1021
|
+
cursor: args.cursor,
|
|
1022
|
+
includeClosed: args['include-closed'],
|
|
1023
|
+
}), args._, 0)(),
|
|
1024
|
+
}),
|
|
1025
|
+
},
|
|
1026
|
+
});
|
|
980
1027
|
return defineCommand({
|
|
981
1028
|
meta: {
|
|
982
1029
|
name: 'nuxtseo',
|
|
@@ -1041,6 +1088,7 @@ export function createRootCommand(runtime, globals, execution) {
|
|
|
1041
1088
|
}),
|
|
1042
1089
|
research,
|
|
1043
1090
|
search,
|
|
1091
|
+
timeline,
|
|
1044
1092
|
},
|
|
1045
1093
|
});
|
|
1046
1094
|
}
|
package/dist/render.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { IndexingDiagnosticsData, SearchAnalyticsData, SearchStatusData } f
|
|
|
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';
|
|
10
|
+
import type { TimelineEntries } from '@nuxtseo/protocol/v1/timeline';
|
|
10
11
|
export declare function renderSites(response: SitesListResponse, selectedSiteId?: string): string;
|
|
11
12
|
export declare function renderUsage(response: AccountUsageResponse): string;
|
|
12
13
|
export declare function renderActions(data: ActionList): string;
|
|
@@ -28,5 +29,6 @@ export declare function renderContentBriefCreated(data: ContentBriefCreateData):
|
|
|
28
29
|
export declare function renderContentDecay(data: AuditContentDecay): string;
|
|
29
30
|
export declare function renderDuplicateClusters(data: AuditDuplicateClusters): string;
|
|
30
31
|
export declare function renderLinkOpportunities(data: AuditLinkOpportunities): string;
|
|
32
|
+
export declare function renderTimeline(data: TimelineEntries): string;
|
|
31
33
|
export declare function renderRecoverableBacklinks(data: RecoverableBacklinks): string;
|
|
32
34
|
export declare function renderMentions(data: Mentions): string;
|
package/dist/render.js
CHANGED
|
@@ -270,6 +270,18 @@ export function renderLinkOpportunities(data) {
|
|
|
270
270
|
...data.rows.map(row => `${row.phrase}\n From: ${row.sourceUrl}\n To: ${row.targetUrl}`),
|
|
271
271
|
].join('\n');
|
|
272
272
|
}
|
|
273
|
+
export function renderTimeline(data) {
|
|
274
|
+
if (data.entries.length === 0)
|
|
275
|
+
return 'No Timeline Entries match these filters.';
|
|
276
|
+
return [
|
|
277
|
+
`Timeline (${data.entries.length})`,
|
|
278
|
+
...data.entries.map((entry) => {
|
|
279
|
+
const label = typeof entry.rendered?.label === 'string' ? entry.rendered.label : entry.kind;
|
|
280
|
+
return `${entry.occurredAt} ${entry.severity ?? 'unrated'} ${entry.kind}\n ${label}`;
|
|
281
|
+
}),
|
|
282
|
+
data.nextCursor ? `More Timeline Entries available — pass --cursor ${JSON.stringify(data.nextCursor)}.` : '',
|
|
283
|
+
].filter(Boolean).join('\n');
|
|
284
|
+
}
|
|
273
285
|
export function renderRecoverableBacklinks(data) {
|
|
274
286
|
if (data.items.length === 0)
|
|
275
287
|
return 'No recoverable Backlinks. Every stored inbound link resolves.';
|
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.4",
|
|
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.4"
|
|
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.4"
|
|
48
48
|
},
|
|
49
49
|
"publishConfig": {
|
|
50
50
|
"access": "public"
|
|
@@ -132,11 +132,11 @@ handling failures, read [CLI protocol](references/protocol.md).
|
|
|
132
132
|
`page inspect` and `page scan` take an absolute URL, for example
|
|
133
133
|
`https://example.com/about`.
|
|
134
134
|
|
|
135
|
-
`--help --json` returns a `CliHelp` value for one command level
|
|
136
|
-
`arguments`,
|
|
137
|
-
|
|
138
|
-
example `nuxtseo actions list --help --json`. Use this instead of
|
|
139
|
-
flag, and prefer the table above for anything it already answers.
|
|
135
|
+
`--help --json` returns a `CliHelp` value for one command level. It separates
|
|
136
|
+
positional `arguments`, command-specific `localOptions`, inherited
|
|
137
|
+
`globalOptions`, and `subcommands`. To learn a subcommand's own flags, ask it
|
|
138
|
+
directly, for example `nuxtseo actions list --help --json`. Use this instead of
|
|
139
|
+
guessing a flag, and prefer the table above for anything it already answers.
|
|
140
140
|
|
|
141
141
|
## The triage loop
|
|
142
142
|
|
|
@@ -18,7 +18,8 @@ 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
|
-
Local outcomes have no server body. They carry
|
|
21
|
+
Local outcomes have no server body. They carry one tag and their own schema
|
|
22
|
+
version. `CliHelp` uses version 2. The other values use version 1.
|
|
22
23
|
|
|
23
24
|
| `_tag` | Written by |
|
|
24
25
|
| --- | --- |
|