@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.
Files changed (44) hide show
  1. package/README.md +218 -0
  2. package/dist/api.d.ts +14 -0
  3. package/dist/api.js +43 -0
  4. package/dist/browser.d.ts +7 -0
  5. package/dist/browser.js +24 -0
  6. package/dist/cli-entry.d.ts +2 -0
  7. package/dist/cli-entry.js +41 -0
  8. package/dist/cli.d.ts +3 -0
  9. package/dist/cli.js +232 -0
  10. package/dist/command-contract.d.ts +33 -0
  11. package/dist/command-contract.js +131 -0
  12. package/dist/commands.d.ts +8 -0
  13. package/dist/commands.js +626 -0
  14. package/dist/failures.d.ts +36 -0
  15. package/dist/failures.js +132 -0
  16. package/dist/index.d.ts +5 -0
  17. package/dist/index.js +3 -0
  18. package/dist/pairing.d.ts +13 -0
  19. package/dist/pairing.js +100 -0
  20. package/dist/parse.d.ts +23 -0
  21. package/dist/parse.js +126 -0
  22. package/dist/render.d.ts +17 -0
  23. package/dist/render.js +156 -0
  24. package/dist/runtime.d.ts +18 -0
  25. package/dist/runtime.js +12 -0
  26. package/dist/site.d.ts +5 -0
  27. package/dist/site.js +48 -0
  28. package/dist/state/auth.d.ts +45 -0
  29. package/dist/state/auth.js +232 -0
  30. package/dist/state/config.d.ts +39 -0
  31. package/dist/state/config.js +145 -0
  32. package/dist/state/files.d.ts +6 -0
  33. package/dist/state/files.js +125 -0
  34. package/dist/state/index.d.ts +4 -0
  35. package/dist/state/index.js +4 -0
  36. package/dist/state/paths.d.ts +10 -0
  37. package/dist/state/paths.js +16 -0
  38. package/dist/state/result.d.ts +67 -0
  39. package/dist/state/result.js +6 -0
  40. package/dist/version.d.ts +1 -0
  41. package/dist/version.js +2 -0
  42. package/package.json +62 -0
  43. package/skills/nuxtseo-cli/SKILL.md +162 -0
  44. 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,6 @@
1
+ export function ok(value) {
2
+ return { _tag: 'Ok', value };
3
+ }
4
+ export function err(error) {
5
+ return { _tag: 'Err', error };
6
+ }
@@ -0,0 +1 @@
1
+ export declare const VERSION: string;
@@ -0,0 +1,2 @@
1
+ import manifest from '../package.json' with { type: 'json' };
2
+ export const VERSION = manifest.version;
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.