@nuxtseo/cli 0.1.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 +218 -0
- package/dist/api.d.ts +14 -0
- package/dist/api.js +43 -0
- package/dist/browser.d.ts +7 -0
- package/dist/browser.js +24 -0
- package/dist/cli-entry.d.ts +2 -0
- package/dist/cli-entry.js +41 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +232 -0
- package/dist/command-contract.d.ts +33 -0
- package/dist/command-contract.js +131 -0
- package/dist/commands.d.ts +8 -0
- package/dist/commands.js +626 -0
- package/dist/failures.d.ts +36 -0
- package/dist/failures.js +132 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +3 -0
- package/dist/pairing.d.ts +13 -0
- package/dist/pairing.js +100 -0
- package/dist/parse.d.ts +23 -0
- package/dist/parse.js +126 -0
- package/dist/render.d.ts +17 -0
- package/dist/render.js +156 -0
- package/dist/runtime.d.ts +18 -0
- package/dist/runtime.js +12 -0
- package/dist/site.d.ts +5 -0
- package/dist/site.js +48 -0
- package/dist/state/auth.d.ts +45 -0
- package/dist/state/auth.js +232 -0
- package/dist/state/config.d.ts +39 -0
- package/dist/state/config.js +145 -0
- package/dist/state/files.d.ts +6 -0
- package/dist/state/files.js +125 -0
- package/dist/state/index.d.ts +4 -0
- package/dist/state/index.js +4 -0
- package/dist/state/paths.d.ts +10 -0
- package/dist/state/paths.js +16 -0
- package/dist/state/result.d.ts +67 -0
- package/dist/state/result.js +6 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +2 -0
- package/package.json +62 -0
- package/skills/nuxtseo-cli/SKILL.md +162 -0
- package/skills/nuxtseo-cli/references/protocol.md +64 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export type StateKind = 'auth' | 'config';
|
|
2
|
+
export type StateOperation = 'read' | 'write' | 'delete';
|
|
3
|
+
export interface CorruptConfigError {
|
|
4
|
+
_tag: 'CorruptConfig';
|
|
5
|
+
path: string;
|
|
6
|
+
message: string;
|
|
7
|
+
cause?: unknown;
|
|
8
|
+
}
|
|
9
|
+
export interface CorruptAuthError {
|
|
10
|
+
_tag: 'CorruptAuth';
|
|
11
|
+
path: string;
|
|
12
|
+
message: string;
|
|
13
|
+
cause?: unknown;
|
|
14
|
+
}
|
|
15
|
+
export interface ReadOnlyFilesystemError {
|
|
16
|
+
_tag: 'ReadOnlyFilesystem';
|
|
17
|
+
kind: StateKind;
|
|
18
|
+
operation: Exclude<StateOperation, 'read'>;
|
|
19
|
+
path: string;
|
|
20
|
+
message: string;
|
|
21
|
+
cause?: unknown;
|
|
22
|
+
}
|
|
23
|
+
export interface StateFilesystemError {
|
|
24
|
+
_tag: 'StateFilesystemError';
|
|
25
|
+
kind: StateKind;
|
|
26
|
+
operation: StateOperation;
|
|
27
|
+
path: string;
|
|
28
|
+
message: string;
|
|
29
|
+
cause?: unknown;
|
|
30
|
+
}
|
|
31
|
+
export interface InvalidApiUrlError {
|
|
32
|
+
_tag: 'InvalidApiUrl';
|
|
33
|
+
source: 'argument' | 'environment';
|
|
34
|
+
message: string;
|
|
35
|
+
}
|
|
36
|
+
export interface InvalidConfigError {
|
|
37
|
+
_tag: 'InvalidConfig';
|
|
38
|
+
message: string;
|
|
39
|
+
}
|
|
40
|
+
export interface InvalidCredentialError {
|
|
41
|
+
_tag: 'InvalidCredential';
|
|
42
|
+
source: 'input' | 'environment';
|
|
43
|
+
message: string;
|
|
44
|
+
}
|
|
45
|
+
export interface KeychainUnavailableError {
|
|
46
|
+
_tag: 'KeychainUnavailable';
|
|
47
|
+
path: string;
|
|
48
|
+
message: string;
|
|
49
|
+
cause?: unknown;
|
|
50
|
+
}
|
|
51
|
+
export interface KeychainFailureError {
|
|
52
|
+
_tag: 'KeychainFailure';
|
|
53
|
+
operation: 'read' | 'write' | 'delete';
|
|
54
|
+
path: string;
|
|
55
|
+
message: string;
|
|
56
|
+
cause?: unknown;
|
|
57
|
+
}
|
|
58
|
+
export type StateError = CorruptConfigError | CorruptAuthError | ReadOnlyFilesystemError | StateFilesystemError | InvalidApiUrlError | InvalidConfigError | InvalidCredentialError | KeychainUnavailableError | KeychainFailureError;
|
|
59
|
+
export type StateResult<TValue, TError = StateError> = {
|
|
60
|
+
_tag: 'Ok';
|
|
61
|
+
value: TValue;
|
|
62
|
+
} | {
|
|
63
|
+
_tag: 'Err';
|
|
64
|
+
error: TError;
|
|
65
|
+
};
|
|
66
|
+
export declare function ok<TValue>(value: TValue): StateResult<TValue, never>;
|
|
67
|
+
export declare function err<TError>(error: TError): StateResult<never, TError>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const VERSION: string;
|
package/dist/version.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nuxtseo/cli",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Command line interface for the NuxtSEO public API.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://nuxtseo.com/pro",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/harlan-zw/nuxtseo.com.git",
|
|
11
|
+
"directory": "packages/cli"
|
|
12
|
+
},
|
|
13
|
+
"sideEffects": [
|
|
14
|
+
"./dist/cli-entry.js"
|
|
15
|
+
],
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"bin": {
|
|
24
|
+
"nuxtseo": "./dist/cli-entry.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"skills"
|
|
29
|
+
],
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=22"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@nuxtseo/sdk": "^0.1.0"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@clack/prompts": "^1.7.0",
|
|
38
|
+
"citty": "^0.2.2",
|
|
39
|
+
"pathe": "^2.0.3"
|
|
40
|
+
},
|
|
41
|
+
"optionalDependencies": {
|
|
42
|
+
"@napi-rs/keyring": "^1.3.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@arethetypeswrong/cli": "^0.18.5",
|
|
46
|
+
"@types/node": "^26.2.0",
|
|
47
|
+
"publint": "^0.3.23",
|
|
48
|
+
"typescript": "npm:typescript-native-bridge@6.0.3-bridge.10.tsgo.7.0.2",
|
|
49
|
+
"@nuxtseo/protocol": "0.1.0",
|
|
50
|
+
"@nuxtseo/sdk": "0.1.0"
|
|
51
|
+
},
|
|
52
|
+
"publishConfig": {
|
|
53
|
+
"access": "public"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "node scripts/build.mjs",
|
|
57
|
+
"typecheck": "tsc --noEmit",
|
|
58
|
+
"check:attw": "attw --pack --profile esm-only",
|
|
59
|
+
"check:publint": "publint --pack npm",
|
|
60
|
+
"check:package": "pnpm run build && pnpm run check:publint && pnpm run check:attw"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nuxtseo-cli
|
|
3
|
+
description: Drive the `nuxtseo` CLI (@nuxtseo/cli) to read and act on the NuxtSEO Pro data a Site already stores - next actions, page observations, Lighthouse and Core Web Vitals, Search Console sync state, and account usage. Use this whenever the user mentions NuxtSEO, `nuxtseo`, "what should I fix on my site", next actions, page scans, or asks you to check or resolve stored SEO issues, even when they do not name the CLI. Also use it before writing any script or CI step that shells out to `nuxtseo`. The CLI does NOT do research work; keyword ideas, SERP analysis, Search Console query and page data, rank tracking, competitors, and content briefs live in the `nuxt-seo-pro` MCP server instead, and this skill says which tool to reach for.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# NuxtSEO CLI
|
|
7
|
+
|
|
8
|
+
`nuxtseo` reads a Site through the NuxtSEO public API. Every command goes
|
|
9
|
+
through `@nuxtseo/sdk`. The CLI never calls MCP, private routes, or providers,
|
|
10
|
+
so it has no hidden fallback: what it prints is what the API returned.
|
|
11
|
+
|
|
12
|
+
Use it to answer "what is wrong with this site and what did I break", then fix
|
|
13
|
+
the code in the repo you are working in.
|
|
14
|
+
|
|
15
|
+
## What this CLI does not cover
|
|
16
|
+
|
|
17
|
+
The CLI reads what the product already stored for a Site. It runs no research.
|
|
18
|
+
|
|
19
|
+
| The user wants | Reach for |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| Keyword ideas, volume, difficulty, SERP analysis | MCP `keyword_research`, `domain_info` |
|
|
22
|
+
| Search Console queries, pages, striking distance | MCP `gsc_query` |
|
|
23
|
+
| Rank history for tracked keywords | MCP `rank_tracker` |
|
|
24
|
+
| Competitors, mentions, backlinks, link opportunities | MCP `competitors`, `mentions`, `backlinks`, `link_opportunities` |
|
|
25
|
+
| Content briefs, content decay, duplicate clusters | MCP `content_briefs`, `content_decay`, `duplicate_clusters` |
|
|
26
|
+
|
|
27
|
+
Those tools come from the `nuxt-seo-pro` MCP server, which the user connects
|
|
28
|
+
separately. If the MCP server is not connected and the job is research shaped,
|
|
29
|
+
say so and stop. Do not approximate research output from CLI data.
|
|
30
|
+
|
|
31
|
+
`nuxtseo search status` reports only whether Search Console is connected and how
|
|
32
|
+
far the sync got. It returns no query rows.
|
|
33
|
+
|
|
34
|
+
## Get the binary
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
npx -y @nuxtseo/cli@latest --version # no install
|
|
38
|
+
pnpm add -g @nuxtseo/cli # or npm install --global
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Node 22 or newer is required. Inside the NuxtSEO monorepo itself, the package is
|
|
42
|
+
not published, so run the built entry directly:
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
node packages/cli/dist/cli-entry.js --version
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Exit `127` or `command not found` means the CLI is absent. That is not exit `3`;
|
|
49
|
+
no token has been checked yet. Install it, then continue.
|
|
50
|
+
|
|
51
|
+
## Before the first command
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
nuxtseo whoami --json # validates the token, lists Site count
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Exit `3` means there is no working token. Ask the user to run `nuxtseo login`
|
|
58
|
+
themselves: it opens a browser, they approve the pairing, and the CLI stores the
|
|
59
|
+
token. Do not run `login` for them; it needs a person at the browser, and in a
|
|
60
|
+
non-interactive shell it falls back to reading a token from stdin instead.
|
|
61
|
+
|
|
62
|
+
The alternative is a token created at
|
|
63
|
+
<https://nuxtseo.com/pro/dashboard/settings/api-tokens> and exported as
|
|
64
|
+
`NUXTSEO_TOKEN`. Either way the token is bound to a Team role, and that role
|
|
65
|
+
gates what it can do.
|
|
66
|
+
|
|
67
|
+
Never put a token in a command argument, a file you write, or a commit. `login`
|
|
68
|
+
reads a token from a hidden prompt or stdin only.
|
|
69
|
+
|
|
70
|
+
Resolve the Site once and reuse it. `nuxtseo sites list --json` prints every
|
|
71
|
+
accessible Site with its ID.
|
|
72
|
+
|
|
73
|
+
## How to call it as an agent
|
|
74
|
+
|
|
75
|
+
Always pass `--json` and always pass `--site <site-id>`.
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
nuxtseo actions list --site site_123 --json
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`--json` writes the complete protocol envelope to stdout and one newline. It
|
|
82
|
+
also disables prompts. Diagnostics, warnings, spinners, and failure messages go
|
|
83
|
+
to stderr, so stdout stays parseable.
|
|
84
|
+
|
|
85
|
+
`--site` matters for a second reason: an explicit Site ID goes straight to the
|
|
86
|
+
operation and skips the Sites read, so a token whose role cannot list Sites
|
|
87
|
+
still works. If more than one Site is accessible and `--site` is absent, the CLI
|
|
88
|
+
exits `5` rather than guessing.
|
|
89
|
+
|
|
90
|
+
Other flags worth knowing:
|
|
91
|
+
|
|
92
|
+
| Flag | Use it when |
|
|
93
|
+
| --- | --- |
|
|
94
|
+
| `--yes`, `-y` | The command mutates. Without it, a non-interactive run exits `2`. |
|
|
95
|
+
| `--timeout-ms <ms>` | The default 30000 ms deadline is too short. Maximum is 300000. |
|
|
96
|
+
| `--api-url <url>` | Testing against a non-production host. |
|
|
97
|
+
| `--no-input` | Running in a TTY but no prompt is wanted. `--json` already implies this. |
|
|
98
|
+
|
|
99
|
+
Unknown options exit `2` before any network work, so a typo costs nothing.
|
|
100
|
+
|
|
101
|
+
Parse JSON. Never scrape human output. Before parsing envelopes, paging, or
|
|
102
|
+
handling failures, read [CLI protocol](references/protocol.md).
|
|
103
|
+
|
|
104
|
+
## Commands
|
|
105
|
+
|
|
106
|
+
| Command | Reads | Notes |
|
|
107
|
+
| --- | --- | --- |
|
|
108
|
+
| `whoami` | Token validity, API host, Site count | Cheapest health check |
|
|
109
|
+
| `sites list` | Every accessible Site | Source of Site IDs |
|
|
110
|
+
| `sites use <site-id>` | – | Persists a default Site for the human, not for you |
|
|
111
|
+
| `usage` | Plan and meters | `--group integrations\|compute\|capacity` |
|
|
112
|
+
| `actions list` | Server ranked next actions | `--limit 1..25` (default 10), `--offset` |
|
|
113
|
+
| `actions show <action-id>` | One action plus evidence | `--limit 1..100` (default 50), `--group-id`, `--cursor` |
|
|
114
|
+
| `actions resolve <action-id>` | – | Mutation. Claims the action and starts server verification |
|
|
115
|
+
| `page inspect <url>` | Stored observations, Lighthouse, keywords | `--limit 1..200`, `--offset`, `--include-resolved` |
|
|
116
|
+
| `page scan <url>` | – | Mutation. Starts mobile and desktop scans |
|
|
117
|
+
| `performance` | Site performance overview | Medians for perf, a11y, SEO, LCP, TBT, CLS |
|
|
118
|
+
| `search status` | Search Console connection and sync progress | Check this before trusting search data |
|
|
119
|
+
| `config` | Local config path, API host, selected Site | Local only |
|
|
120
|
+
|
|
121
|
+
`page inspect` and `page scan` take an absolute URL, for example
|
|
122
|
+
`https://example.com/about`.
|
|
123
|
+
|
|
124
|
+
`--help --json` returns a `CliHelp` value for one command level: its
|
|
125
|
+
`arguments`, the inherited `globalOptions`, and its `subcommands` as names and
|
|
126
|
+
descriptions only. To learn a subcommand's own flags, ask it directly, for
|
|
127
|
+
example `nuxtseo actions list --help --json`. Use this instead of guessing a
|
|
128
|
+
flag, and prefer the table above for anything it already answers.
|
|
129
|
+
|
|
130
|
+
## The triage loop
|
|
131
|
+
|
|
132
|
+
This is the sequence that turns CLI output into a code change:
|
|
133
|
+
|
|
134
|
+
1. `nuxtseo actions list --site <id> --json` gives ranked work with an ID, a
|
|
135
|
+
diagnosis, an effort, and an affected page count.
|
|
136
|
+
2. `nuxtseo actions show <action-id> --site <id> --json` gives the evidence:
|
|
137
|
+
which pages, which finding type, and when it was observed.
|
|
138
|
+
3. Fix the cause in the repository. The evidence names URLs; map them back to
|
|
139
|
+
routes, components, or config.
|
|
140
|
+
4. Deploy or preview the fix, then `nuxtseo page scan <url> --site <id> --yes
|
|
141
|
+
--json` to ask for fresh scans of a page you changed.
|
|
142
|
+
5. `nuxtseo actions resolve <action-id> --site <id> --yes --json` claims the
|
|
143
|
+
action. The server verifies it; the CLI does not mark anything fixed by
|
|
144
|
+
itself.
|
|
145
|
+
|
|
146
|
+
Resolve reads the action first and sends the current `artifactVersion` for you.
|
|
147
|
+
Do not construct that field by hand. If the evidence moved under you, the
|
|
148
|
+
command exits `5` with `stale_evidence`; re-run step 2 and decide again.
|
|
149
|
+
|
|
150
|
+
## Guardrails
|
|
151
|
+
|
|
152
|
+
- Ask before you mutate. `actions resolve` and `page scan` consume quota and
|
|
153
|
+
change server state. `--yes` is consent you are borrowing from the user, so
|
|
154
|
+
get it first unless the user already asked for that exact action.
|
|
155
|
+
- Do not loop over pages or URLs unattended. Each call is a real API request
|
|
156
|
+
against a metered plan. Check `nuxtseo usage --json` if you plan a batch.
|
|
157
|
+
- Report failures as they are. The CLI has no cache and no fallback path, so a
|
|
158
|
+
failure means the data is genuinely unavailable, not that another route may
|
|
159
|
+
work.
|
|
160
|
+
- Do not treat an empty result as a clean bill of health. `search status` may
|
|
161
|
+
report an unfinished sync, and a Page with no stored observations may simply
|
|
162
|
+
never have been crawled.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# CLI protocol
|
|
2
|
+
|
|
3
|
+
Read this before parsing output, paging, or handling a nonzero exit.
|
|
4
|
+
|
|
5
|
+
## Response shape
|
|
6
|
+
|
|
7
|
+
Success:
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{ "data": { }, "meta": { "requestId": "...", "version": "1.0" } }
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Protocol failure, still on stdout, with recovery details on stderr:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{ "error": { "code": "rate_limited", "message": "...", "requestId": "...", "retryable": true, "details": {} } }
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Read `data`. The CLI does not unwrap, rename, rank, or enrich fields.
|
|
20
|
+
|
|
21
|
+
Local outcomes have no server body. They carry `schemaVersion: 1` and one tag:
|
|
22
|
+
|
|
23
|
+
| `_tag` | Written by |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| `CliStatus` | Bare `nuxtseo --json` |
|
|
26
|
+
| `CliVersion` | `--version --json` |
|
|
27
|
+
| `CliHelp` | `--help --json` |
|
|
28
|
+
| `CliConfig` | `config --json` |
|
|
29
|
+
| `CliLogout` | `logout --json` |
|
|
30
|
+
| `CliSiteSelection` | `sites use <site-id> --json` |
|
|
31
|
+
| `CliError` | Any failure with no server body |
|
|
32
|
+
|
|
33
|
+
Discriminate on `_tag`. Protocol envelopes never carry one.
|
|
34
|
+
|
|
35
|
+
## Paging
|
|
36
|
+
|
|
37
|
+
One invocation makes one request. The CLI never auto-pages or merges responses.
|
|
38
|
+
|
|
39
|
+
Pass the reported `offset` or opaque `cursor` for another page. Never edit or
|
|
40
|
+
infer a cursor. Keep server order for actions. Never re-rank merged results.
|
|
41
|
+
|
|
42
|
+
## Exit codes
|
|
43
|
+
|
|
44
|
+
Branch on the exit code, not message text.
|
|
45
|
+
|
|
46
|
+
| Code | Meaning | Action |
|
|
47
|
+
| ---: | --- | --- |
|
|
48
|
+
| `0` | Success, including a closed stdout pipe | Continue |
|
|
49
|
+
| `2` | Invalid input, or mutation without `--yes` | Fix arguments. Do not retry unchanged |
|
|
50
|
+
| `3` | Missing, invalid, or expired authentication | Ask the user for a token |
|
|
51
|
+
| `4` | Forbidden, scope, or entitlement failure | Report the plan or token blocker |
|
|
52
|
+
| `5` | Conflict, stale evidence, or ambiguous Site | Re-read. Pass `--site` if ambiguous |
|
|
53
|
+
| `6` | Rate limit, quota, provider outage, or timeout | Read retry metadata, then wait |
|
|
54
|
+
| `7` | Local state, network, contract, or infrastructure failure | Report it with the request ID |
|
|
55
|
+
| `8` | Resource or Site not found | Run `sites list` for a valid Site ID |
|
|
56
|
+
| `127` | Shell cannot find `nuxtseo` | Install the CLI |
|
|
57
|
+
| `130` | Interrupted or cancelled | Check whether a mutation ran before retrying |
|
|
58
|
+
|
|
59
|
+
API failure details on stderr include the server code and request ID. They may
|
|
60
|
+
include retry delay, policy, quota, reset time, and structured details. Keep the
|
|
61
|
+
request ID when reporting a problem.
|
|
62
|
+
|
|
63
|
+
Only exit `6` means the same command may work later. The SDK already retried
|
|
64
|
+
HTTP 429 responses. Mutations are never retried automatically.
|