@rankcli/cli 0.0.29 → 0.0.31

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 CHANGED
@@ -25,7 +25,7 @@ scoop bucket add integrallis https://github.com/integrallis/scoop-bucket
25
25
  scoop install rankcli
26
26
  ```
27
27
 
28
- Or via npm (requires Node 18+):
28
+ Or via npm (requires Node 20.19+ or 22.12+ - see [Node versions](#node-versions)):
29
29
 
30
30
  ```bash
31
31
  npm install -g @rankcli/cli
@@ -59,7 +59,7 @@ rankcli audit --url https://yoursite.com --max-pages 5
59
59
  Check if AI crawlers can access your site:
60
60
 
61
61
  ```bash
62
- rankcli audit --url https://yoursite.com --geo
62
+ rankcli geo --url https://yoursite.com
63
63
  ```
64
64
 
65
65
  Analyzes:
@@ -134,11 +134,68 @@ Options:
134
134
  -u, --url <url> URL to audit
135
135
  -o, --output <format> Output: json, console (default: console)
136
136
  --max-pages <n> Max pages to crawl (default: 5)
137
- --geo Include GEO analysis
138
137
  --check-links Check broken links
139
- --ai AI-powered analysis
138
+ --fail-on <level> CI gate: exit 1 on any issue at/above error | warning | notice
139
+ --min-score <n> CI gate: exit 1 if the overall score is below n (0-100)
140
+ --ai AI-powered analysis (your own key, or a local model)
141
+ --ai-provider <p> See "AI analysis" below (auto-detected if omitted)
142
+ --ai-key <key> Provider API key (or the provider's env var)
143
+ --ai-model <model> Override the provider's default model
144
+ --ai-base-url <url> Any OpenAI-compatible server (implies --ai-provider custom)
140
145
  ```
141
146
 
147
+ #### Exit codes
148
+
149
+ | Code | Meaning |
150
+ |------|---------|
151
+ | `0` | Audit completed; no `--fail-on` / `--min-score` gate tripped |
152
+ | `1` | A `--fail-on` or `--min-score` gate tripped |
153
+ | `2` | Bad invocation: missing/invalid `--url`, invalid flag value |
154
+ | `3` | No real audit: the site was unreachable, the URL answered 4xx/5xx, no page could be analyzed, or an internal error |
155
+
156
+ The gates are opt-in: without them, a completed audit exits `0` however many issues it finds. An unreachable site or an error status always exits `3` - it scores 0, not a passing grade. With `-o json`, stdout is always one JSON document (on failure too) carrying `exitCode` and, when gates are set, a `gate` object with the reasons.
157
+
158
+ #### AI analysis (`--ai`)
159
+
160
+ AI analysis runs on your own provider - nothing goes through RankCLI. With no `--ai-provider`, the first key found wins, in this order (OpenRouter first):
161
+
162
+ | Provider | Env var | Base URL | Default model |
163
+ |----------|---------|----------|---------------|
164
+ | `openrouter` | `OPENROUTER_API_KEY` | `https://openrouter.ai/api/v1` | `openrouter/free` |
165
+ | `groq` | `GROQ_API_KEY` | `https://api.groq.com/openai/v1` | `llama-3.3-70b-versatile` |
166
+ | `gemini` | `GEMINI_API_KEY` / `GOOGLE_API_KEY` | `https://generativelanguage.googleapis.com/v1beta/openai` | `gemini-3.7-flash` |
167
+ | `deepseek` | `DEEPSEEK_API_KEY` | `https://api.deepseek.com` | `deepseek-flash` |
168
+ | `cerebras` | `CEREBRAS_API_KEY` | `https://api.cerebras.ai/v1` | `gpt-oss-120b` |
169
+ | `mistral` | `MISTRAL_API_KEY` | `https://api.mistral.ai/v1` | `mistral-small-latest` |
170
+ | `together` | `TOGETHER_API_KEY` | `https://api.together.xyz/v1` | `openai/gpt-oss-120b` |
171
+ | `fireworks` | `FIREWORKS_API_KEY` | `https://api.fireworks.ai/inference/v1` | `accounts/fireworks/models/gpt-oss-120b` |
172
+ | `anthropic` | `ANTHROPIC_API_KEY` | `https://api.anthropic.com/v1` | `claude-haiku-4-5-20251001` |
173
+ | `openai` | `OPENAI_API_KEY` | `https://api.openai.com/v1` | `gpt-5.6-luna` |
174
+
175
+ **Local models, no key.** If no key is set at all and [Ollama](https://ollama.com) is running, `--ai` uses it automatically (with a one-line notice) and picks its first installed model:
176
+
177
+ ```bash
178
+ ollama pull qwen3:8b
179
+ rankcli audit --url https://yoursite.com --ai # finds Ollama on :11434
180
+ rankcli audit --url https://yoursite.com --ai --ai-provider ollama --ai-model qwen3:8b
181
+ ```
182
+
183
+ | Provider | Default base URL |
184
+ |----------|------------------|
185
+ | `ollama` | `http://localhost:11434/v1` (honours `OLLAMA_HOST`) |
186
+ | `lmstudio` | `http://localhost:1234/v1` |
187
+ | `llamacpp` | `http://localhost:8080/v1` (`llama-server`) |
188
+ | `vllm` | `http://localhost:8000/v1` |
189
+ | `custom` | whatever `--ai-base-url` says |
190
+
191
+ Local providers need no key and no model name: without `--ai-model` the CLI asks the server (`/api/tags` for Ollama, `/v1/models` otherwise) and uses the first loaded model. Any other OpenAI-compatible server works too:
192
+
193
+ ```bash
194
+ rankcli audit --url https://yoursite.com --ai --ai-base-url http://gpu-box:8080/v1 --ai-model my-model
195
+ ```
196
+
197
+ Local and small models often ignore "JSON only" instructions, so the reply is parsed defensively (code fences, `<think>` blocks and surrounding prose are stripped). `response_format: json_object` is only sent to providers known to support it. An AI failure is reported but never changes the exit code.
198
+
142
199
  ### `rankcli apply`
143
200
 
144
201
  Generate and apply framework-specific fixes.
@@ -171,11 +228,12 @@ rankcli content --url https://mysite.com/blog --keyword 'seo tips'
171
228
  # Interactive login
172
229
  rankcli login
173
230
 
174
- # API key (for CI/CD)
231
+ # API key (for CI/CD) - validates the key and resolves your plan; exits 1 if rejected
175
232
  rankcli login --token rankcli_your_api_key
176
233
 
177
- # Or environment variable
234
+ # Or just the environment variable - every command resolves the key's plan itself
178
235
  export RANKCLI_API_KEY=rankcli_your_api_key
236
+ rankcli login # optional: validates it and shows the plan
179
237
  ```
180
238
 
181
239
  ## CI/CD Integration
@@ -190,34 +248,43 @@ jobs:
190
248
  audit:
191
249
  runs-on: ubuntu-latest
192
250
  steps:
193
- - uses: actions/checkout@v4
251
+ - uses: actions/setup-node@v4
252
+ with:
253
+ node-version: '22'
194
254
  - run: npm install -g @rankcli/cli
195
- - run: rankcli audit --url ${{ secrets.SITE_URL }} -o json > audit.json
255
+ # Fails the job on any error-severity issue or a score under 80.
256
+ - run: rankcli audit --url "$SITE_URL" --fail-on error --min-score 80 -o json > "$RUNNER_TEMP/audit.json"
196
257
  env:
197
- RANKCLI_API_KEY: ${{ secrets.RANKCLI_API_KEY }}
198
- - name: Fail on critical issues
199
- run: |
200
- errors=$(jq '.issues | map(select(.severity == "error")) | length' audit.json)
201
- [ "$errors" -eq 0 ] || exit 1
258
+ SITE_URL: ${{ vars.SITE_URL }}
259
+ RANKCLI_API_KEY: ${{ secrets.RANKCLI_API_KEY }} # optional: dashboard sync + your plan's limits
202
260
  ```
203
261
 
262
+ `rankcli setup --github-action --url https://yoursite.com [--sync]` writes a scheduled workflow that files the report as an issue (and, with `--sync` and a RankCLI API key, opens auto-fix PRs - 3 a month on Free).
263
+
204
264
  ## Environment Variables
205
265
 
206
266
  | Variable | Description |
207
267
  |----------|-------------|
208
- | `RANKCLI_API_KEY` | API key for authentication |
209
- | `OPENAI_API_KEY` | OpenAI API key for AI features |
210
- | `ANTHROPIC_API_KEY` | Anthropic API key (alternative) |
268
+ | `RANKCLI_API_KEY` | API key for authentication (plan resolved automatically) |
269
+ | `RANKCLI_CONFIG_DIR` | Store login/config here instead of the per-user config dir |
270
+ | `OPENROUTER_API_KEY`, `GROQ_API_KEY`, `GEMINI_API_KEY`, `DEEPSEEK_API_KEY`, `CEREBRAS_API_KEY`, `MISTRAL_API_KEY`, `TOGETHER_API_KEY`, `FIREWORKS_API_KEY`, `ANTHROPIC_API_KEY`, `OPENAI_API_KEY` | AI analysis keys (see "AI analysis") |
271
+ | `OLLAMA_HOST` | Where a local Ollama listens (default `localhost:11434`) |
272
+
273
+ ## Node versions
274
+
275
+ The npm package needs **Node 20.19+ or 22.12+** (any 23+ works). The CLI is a CommonJS bundle that `require()`s ESM-only dependencies (chalk, conf, inquirer, open), and those are the first releases that load ES modules through `require()` without a flag. Every Node line still in support (22, 24) qualifies. On an older Node, `rankcli` / `npx @rankcli/cli` stops with a message saying so instead of an `ERR_REQUIRE_ESM` stack trace. The Homebrew/Scoop binaries bundle their own Node and have no requirement.
211
276
 
212
277
  ## Pricing
213
278
 
214
279
  | Feature | Free | Solo+ (from $9/mo) |
215
280
  |---------|------|--------------|
216
- | SEO Checks | 100 | 280+ |
217
- | GEO Analysis | Basic | Full |
218
- | Framework Fixes | - | ✅ 25+ |
219
- | Auto-Fix PRs | - | ✅ |
220
- | Sites | 1 | 3+ |
281
+ | SEO + GEO checks | All 280+ | All 280+ |
282
+ | Local fixes (`rankcli fix`, 25+ frameworks) | ✅ | ✅ |
283
+ | Auto-fix PRs (GitHub App) | 3 a month | ✅ |
284
+ | Hosted sites | 1, audited weekly | 3+, weekly or daily |
285
+ | Slack & Discord alerts | - | ✅ |
286
+
287
+ See [rankcli.dev/pricing](https://rankcli.dev/pricing).
221
288
 
222
289
  ## Links
223
290
 
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // The CLI bundle (dist/index.js) is CommonJS and require()s ESM-only
5
+ // dependencies (chalk 5, conf 12, inquirer 9, open 10). Node runs
6
+ // require() of an ES module without a flag from 20.19 and 22.12 on; older
7
+ // versions crash with ERR_REQUIRE_ESM before printing anything useful.
8
+ // Check first so `npx @rankcli/cli` on an old Node says what to do.
9
+ const [major, minor] = process.versions.node.split('.').map(Number);
10
+ const supported = major >= 23 || (major === 22 && minor >= 12) || (major === 20 && minor >= 19);
11
+
12
+ if (!supported) {
13
+ console.error(`rankcli needs Node.js 20.19+ or 22.12+ (this is ${process.versions.node}).`);
14
+ console.error('Upgrade Node (https://nodejs.org), or use the standalone binary: brew install integrallis/tap/rankcli');
15
+ process.exit(1);
16
+ }
17
+
18
+ require('../dist/index.js');