@rankcli/cli 0.0.30 → 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 +9 -7
- package/dist/index.js +19 -69
- package/dist/index.mjs +19 -69
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -256,10 +256,10 @@ jobs:
|
|
|
256
256
|
- run: rankcli audit --url "$SITE_URL" --fail-on error --min-score 80 -o json > "$RUNNER_TEMP/audit.json"
|
|
257
257
|
env:
|
|
258
258
|
SITE_URL: ${{ vars.SITE_URL }}
|
|
259
|
-
RANKCLI_API_KEY: ${{ secrets.RANKCLI_API_KEY }} # optional:
|
|
259
|
+
RANKCLI_API_KEY: ${{ secrets.RANKCLI_API_KEY }} # optional: dashboard sync + your plan's limits
|
|
260
260
|
```
|
|
261
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
|
|
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
263
|
|
|
264
264
|
## Environment Variables
|
|
265
265
|
|
|
@@ -278,11 +278,13 @@ The npm package needs **Node 20.19+ or 22.12+** (any 23+ works). The CLI is a Co
|
|
|
278
278
|
|
|
279
279
|
| Feature | Free | Solo+ (from $9/mo) |
|
|
280
280
|
|---------|------|--------------|
|
|
281
|
-
| SEO
|
|
282
|
-
|
|
|
283
|
-
|
|
|
284
|
-
|
|
|
285
|
-
|
|
|
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).
|
|
286
288
|
|
|
287
289
|
## Links
|
|
288
290
|
|
package/dist/index.js
CHANGED
|
@@ -45,19 +45,19 @@ var import_node_crypto = require("crypto");
|
|
|
45
45
|
var import_supabase_js = require("@supabase/supabase-js");
|
|
46
46
|
var INJECTED_CONFIG = {"supabaseUrl":"https://bspljbxwbjiqueeyzyat.supabase.co","supabaseAnonKey":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJzcGxqYnh3YmppcXVlZXl6eWF0Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjkyNzQ1NTksImV4cCI6MjA4NDg1MDU1OX0.7gprxM2gT9cZ99sjZURLltrln78dEnwyFFKYpTzBaUU","webAppUrl":"https://rankcli.dev","decryptPassphrase":"lKFLeIw/xGPa6E8c4XswZX/oiLtJf/yLF/Y6zwovte8="};
|
|
47
47
|
function getSupabaseUrl() {
|
|
48
|
-
const url = process.env.RANKCLI_SUPABASE_URL ||
|
|
48
|
+
const url = process.env.RANKCLI_SUPABASE_URL || INJECTED_CONFIG?.supabaseUrl;
|
|
49
49
|
if (!url) {
|
|
50
50
|
throw new Error(
|
|
51
|
-
"Supabase URL not configured. Set RANKCLI_SUPABASE_URL environment variable.\nSee: https://rankcli.dev/docs
|
|
51
|
+
"Supabase URL not configured. Set RANKCLI_SUPABASE_URL environment variable.\nSee: https://rankcli.dev/docs#getting-started"
|
|
52
52
|
);
|
|
53
53
|
}
|
|
54
54
|
return url;
|
|
55
55
|
}
|
|
56
56
|
function getSupabaseAnonKey() {
|
|
57
|
-
const key = process.env.RANKCLI_SUPABASE_ANON_KEY ||
|
|
57
|
+
const key = process.env.RANKCLI_SUPABASE_ANON_KEY || INJECTED_CONFIG?.supabaseAnonKey;
|
|
58
58
|
if (!key) {
|
|
59
59
|
throw new Error(
|
|
60
|
-
"Supabase anon key not configured. Set RANKCLI_SUPABASE_ANON_KEY environment variable.\nSee: https://rankcli.dev/docs
|
|
60
|
+
"Supabase anon key not configured. Set RANKCLI_SUPABASE_ANON_KEY environment variable.\nSee: https://rankcli.dev/docs#getting-started"
|
|
61
61
|
);
|
|
62
62
|
}
|
|
63
63
|
return key;
|
|
@@ -1110,23 +1110,25 @@ var import_chalk4 = __toESM(require("chalk"));
|
|
|
1110
1110
|
var import_chalk3 = __toESM(require("chalk"));
|
|
1111
1111
|
var WEB_APP_URL2 = "https://rankcli.dev";
|
|
1112
1112
|
var TIER_LIMITS = {
|
|
1113
|
+
// Every plan runs every check (pricing-tiers.json: free_audit / free_registered 280). Plans
|
|
1114
|
+
// differ in sites, schedules, pages per audit, PRs and alerts - not in what an audit checks.
|
|
1113
1115
|
free_anon: {
|
|
1114
|
-
checks:
|
|
1116
|
+
checks: 280,
|
|
1115
1117
|
sites: 0,
|
|
1116
1118
|
domains_per_month: 1,
|
|
1117
|
-
features: { geo:
|
|
1119
|
+
features: { geo: true, auto_fix: true, github: false, ai: false }
|
|
1118
1120
|
},
|
|
1119
1121
|
free: {
|
|
1120
|
-
checks:
|
|
1122
|
+
checks: 280,
|
|
1121
1123
|
sites: 1,
|
|
1122
1124
|
domains_per_month: 2,
|
|
1123
|
-
features: { geo:
|
|
1125
|
+
features: { geo: true, auto_fix: true, github: true, ai: false }
|
|
1124
1126
|
},
|
|
1125
1127
|
solo: {
|
|
1126
1128
|
checks: 280,
|
|
1127
1129
|
sites: 3,
|
|
1128
1130
|
domains_per_month: 5,
|
|
1129
|
-
features: { geo: true, auto_fix: true, github:
|
|
1131
|
+
features: { geo: true, auto_fix: true, github: true, ai: true }
|
|
1130
1132
|
},
|
|
1131
1133
|
pro: {
|
|
1132
1134
|
checks: 280,
|
|
@@ -1152,21 +1154,14 @@ var UPSELL_MESSAGES = {
|
|
|
1152
1154
|
free_audit_complete: () => [
|
|
1153
1155
|
"",
|
|
1154
1156
|
import_chalk3.default.yellow("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"),
|
|
1155
|
-
import_chalk3.default.yellow.bold(" \u{1F680}
|
|
1156
|
-
import_chalk3.default.dim("
|
|
1157
|
+
import_chalk3.default.yellow.bold(" \u{1F680} Keep this site audited, free"),
|
|
1158
|
+
import_chalk3.default.dim(" A free account audits one site weekly, keeps the history and"),
|
|
1159
|
+
import_chalk3.default.dim(" emails you a weekly report."),
|
|
1157
1160
|
"",
|
|
1158
1161
|
import_chalk3.default.cyan(` \u2192 rankcli login`),
|
|
1159
1162
|
import_chalk3.default.yellow("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"),
|
|
1160
1163
|
""
|
|
1161
1164
|
],
|
|
1162
|
-
// When checks limit is reached
|
|
1163
|
-
checks_limit: (ctx) => [
|
|
1164
|
-
"",
|
|
1165
|
-
import_chalk3.default.yellow(`\u26A0\uFE0F Running ${ctx.current || 50} of ${TIER_LIMITS.solo.checks} available checks`),
|
|
1166
|
-
import_chalk3.default.dim(` Unlock all ${TIER_LIMITS.solo.checks}+ checks with Solo ($9/mo)`),
|
|
1167
|
-
import_chalk3.default.cyan(` \u2192 ${WEB_APP_URL2}/pricing?from=cli_checks`),
|
|
1168
|
-
""
|
|
1169
|
-
],
|
|
1170
1165
|
// When domain limit is reached
|
|
1171
1166
|
domain_limit: (ctx) => [
|
|
1172
1167
|
"",
|
|
@@ -1179,18 +1174,6 @@ var UPSELL_MESSAGES = {
|
|
|
1179
1174
|
import_chalk3.default.red("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"),
|
|
1180
1175
|
""
|
|
1181
1176
|
],
|
|
1182
|
-
// When GEO features are limited
|
|
1183
|
-
geo_limited: (ctx) => [
|
|
1184
|
-
"",
|
|
1185
|
-
import_chalk3.default.yellow("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"),
|
|
1186
|
-
import_chalk3.default.yellow.bold(" \u{1F916} Full GEO analysis requires Solo"),
|
|
1187
|
-
import_chalk3.default.dim(" You're seeing basic AI crawler access checks."),
|
|
1188
|
-
import_chalk3.default.dim(" Full analysis includes: LLM signals, citation readiness, content structure"),
|
|
1189
|
-
"",
|
|
1190
|
-
import_chalk3.default.cyan(` \u2192 ${WEB_APP_URL2}/pricing?from=cli_geo`),
|
|
1191
|
-
import_chalk3.default.yellow("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"),
|
|
1192
|
-
""
|
|
1193
|
-
],
|
|
1194
1177
|
// When auto-fix is attempted without access
|
|
1195
1178
|
auto_fix_blocked: () => [
|
|
1196
1179
|
"",
|
|
@@ -1291,10 +1274,6 @@ function showUpsell(messageKey, context) {
|
|
|
1291
1274
|
const lines = messageFn(ctx);
|
|
1292
1275
|
lines.forEach((line) => console.log(line));
|
|
1293
1276
|
}
|
|
1294
|
-
function hasFeature(tier, feature) {
|
|
1295
|
-
const limits = TIER_LIMITS[tier];
|
|
1296
|
-
return limits?.features?.[feature] ?? false;
|
|
1297
|
-
}
|
|
1298
1277
|
|
|
1299
1278
|
// src/wasm-engine.ts
|
|
1300
1279
|
var vm = __toESM(require("vm"));
|
|
@@ -1991,7 +1970,7 @@ async function audit(options) {
|
|
|
1991
1970
|
const tierId = tierFromPlanId(planId) ?? (loggedIn ? "free" : "free_anon");
|
|
1992
1971
|
const checksLimit = TIER_LIMITS[tierId].checks;
|
|
1993
1972
|
let premiumChecks;
|
|
1994
|
-
|
|
1973
|
+
{
|
|
1995
1974
|
const passphrase = getDecryptPassphrase();
|
|
1996
1975
|
if (passphrase) {
|
|
1997
1976
|
try {
|
|
@@ -2202,17 +2181,6 @@ async function audit(options) {
|
|
|
2202
2181
|
}
|
|
2203
2182
|
}
|
|
2204
2183
|
console.log("\n" + import_chalk4.default.bold("\u2550".repeat(60)));
|
|
2205
|
-
const isFreeTier = tierId === "free" || tierId === "free_anon";
|
|
2206
|
-
if (isFreeTier) {
|
|
2207
|
-
const checksRun = mergedIssues.length > 0 ? loggedIn ? 100 : 50 : 0;
|
|
2208
|
-
showUpsell("checks_limit", {
|
|
2209
|
-
tier: loggedIn ? "free" : "free_anon",
|
|
2210
|
-
current: checksRun
|
|
2211
|
-
});
|
|
2212
|
-
}
|
|
2213
|
-
if (options.geo && isFreeTier) {
|
|
2214
|
-
showUpsell("geo_limited", { tier: loggedIn ? "free" : "free_anon" });
|
|
2215
|
-
}
|
|
2216
2184
|
if (loggedIn) {
|
|
2217
2185
|
const syncSpinner = (0, import_ora2.default)("Syncing to cloud...").start();
|
|
2218
2186
|
const syncResult = await syncToCloud(url, primaryReport, mergedIssues, successCount, aiAnalysis, totalTime, actualChecksRun);
|
|
@@ -2326,14 +2294,6 @@ async function apply(options) {
|
|
|
2326
2294
|
}
|
|
2327
2295
|
console.log("\n\u{1F680} RankCLI - Apply Fixes");
|
|
2328
2296
|
console.log("\u2550".repeat(50));
|
|
2329
|
-
const loggedIn = isLoggedIn();
|
|
2330
|
-
const userInfo = getUserInfo();
|
|
2331
|
-
const tier = userInfo.planName?.toLowerCase() || "free";
|
|
2332
|
-
const hasAutoFix = loggedIn && hasFeature(tier, "auto_fix");
|
|
2333
|
-
if (!hasAutoFix) {
|
|
2334
|
-
showUpsell("auto_fix_blocked");
|
|
2335
|
-
return;
|
|
2336
|
-
}
|
|
2337
2297
|
console.log("\n\u{1F50D} Detecting framework...");
|
|
2338
2298
|
const frameworkResult = await (0, import_agent_runtime3.detectFramework)({ cwd });
|
|
2339
2299
|
const framework = frameworkResult.success ? frameworkResult.data : { name: "Unknown", metaPattern: "html-head" };
|
|
@@ -2589,16 +2549,6 @@ async function runFix(options) {
|
|
|
2589
2549
|
if (loggedIn) await ensureApiKeyPlan();
|
|
2590
2550
|
const userInfo = getUserInfo();
|
|
2591
2551
|
const tier = tierFromPlanId(userInfo.planId) ?? tierFromPlanId(userInfo.planName) ?? "free";
|
|
2592
|
-
const hasAutoFix = loggedIn && hasFeature(tier, "auto_fix");
|
|
2593
|
-
if (!options.dryRun && !hasAutoFix) {
|
|
2594
|
-
if (options.output !== "json") {
|
|
2595
|
-
showUpsell("auto_fix_blocked");
|
|
2596
|
-
}
|
|
2597
|
-
return {
|
|
2598
|
-
success: false,
|
|
2599
|
-
error: "Auto-fix requires Solo tier or higher. Please upgrade at " + WEB_APP_URL + "/account"
|
|
2600
|
-
};
|
|
2601
|
-
}
|
|
2602
2552
|
if (options.output !== "json") {
|
|
2603
2553
|
console.log("\n\u{1F527} RankCLI Fix - Agentic SEO Fixer");
|
|
2604
2554
|
console.log("\u2550".repeat(50));
|
|
@@ -3917,7 +3867,7 @@ async function alerts(options) {
|
|
|
3917
3867
|
if (options.list) {
|
|
3918
3868
|
console.log("\u{1F4CB} Current alert configurations:\n");
|
|
3919
3869
|
console.log(" (Alert configs are stored in your RankCLI account)");
|
|
3920
|
-
console.log(" Run `rankcli
|
|
3870
|
+
console.log(" Run `rankcli login` first, then manage alerts at https://rankcli.dev/account?tab=notifications\n");
|
|
3921
3871
|
rl.close();
|
|
3922
3872
|
return;
|
|
3923
3873
|
}
|
|
@@ -3992,8 +3942,8 @@ async function alerts(options) {
|
|
|
3992
3942
|
}
|
|
3993
3943
|
console.log("");
|
|
3994
3944
|
console.log("To save this configuration:");
|
|
3995
|
-
console.log("1. Log in with `rankcli
|
|
3996
|
-
console.log("2. Add alert config at https://rankcli.dev/account
|
|
3945
|
+
console.log("1. Log in with `rankcli login`");
|
|
3946
|
+
console.log("2. Add alert config at https://rankcli.dev/account?tab=notifications");
|
|
3997
3947
|
console.log("");
|
|
3998
3948
|
console.log("Or use the API:");
|
|
3999
3949
|
console.log(` POST /api/alerts with webhook_url and settings`);
|
|
@@ -4052,7 +4002,7 @@ async function testWebhook(channel, webhookUrl) {
|
|
|
4052
4002
|
}
|
|
4053
4003
|
|
|
4054
4004
|
// src/version.ts
|
|
4055
|
-
var VERSION = "0.0.
|
|
4005
|
+
var VERSION = "0.0.31";
|
|
4056
4006
|
|
|
4057
4007
|
// src/index.ts
|
|
4058
4008
|
var program = new import_commander.Command();
|
package/dist/index.mjs
CHANGED
|
@@ -26,19 +26,19 @@ import { createHash } from "crypto";
|
|
|
26
26
|
import { createClient } from "@supabase/supabase-js";
|
|
27
27
|
const INJECTED_CONFIG = {"supabaseUrl":"https://bspljbxwbjiqueeyzyat.supabase.co","supabaseAnonKey":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJzcGxqYnh3YmppcXVlZXl6eWF0Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjkyNzQ1NTksImV4cCI6MjA4NDg1MDU1OX0.7gprxM2gT9cZ99sjZURLltrln78dEnwyFFKYpTzBaUU","webAppUrl":"https://rankcli.dev","decryptPassphrase":"lKFLeIw/xGPa6E8c4XswZX/oiLtJf/yLF/Y6zwovte8="};
|
|
28
28
|
function getSupabaseUrl() {
|
|
29
|
-
const url = process.env.RANKCLI_SUPABASE_URL ||
|
|
29
|
+
const url = process.env.RANKCLI_SUPABASE_URL || INJECTED_CONFIG?.supabaseUrl;
|
|
30
30
|
if (!url) {
|
|
31
31
|
throw new Error(
|
|
32
|
-
"Supabase URL not configured. Set RANKCLI_SUPABASE_URL environment variable.\nSee: https://rankcli.dev/docs
|
|
32
|
+
"Supabase URL not configured. Set RANKCLI_SUPABASE_URL environment variable.\nSee: https://rankcli.dev/docs#getting-started"
|
|
33
33
|
);
|
|
34
34
|
}
|
|
35
35
|
return url;
|
|
36
36
|
}
|
|
37
37
|
function getSupabaseAnonKey() {
|
|
38
|
-
const key = process.env.RANKCLI_SUPABASE_ANON_KEY ||
|
|
38
|
+
const key = process.env.RANKCLI_SUPABASE_ANON_KEY || INJECTED_CONFIG?.supabaseAnonKey;
|
|
39
39
|
if (!key) {
|
|
40
40
|
throw new Error(
|
|
41
|
-
"Supabase anon key not configured. Set RANKCLI_SUPABASE_ANON_KEY environment variable.\nSee: https://rankcli.dev/docs
|
|
41
|
+
"Supabase anon key not configured. Set RANKCLI_SUPABASE_ANON_KEY environment variable.\nSee: https://rankcli.dev/docs#getting-started"
|
|
42
42
|
);
|
|
43
43
|
}
|
|
44
44
|
return key;
|
|
@@ -1097,23 +1097,25 @@ import chalk4 from "chalk";
|
|
|
1097
1097
|
import chalk3 from "chalk";
|
|
1098
1098
|
var WEB_APP_URL2 = "https://rankcli.dev";
|
|
1099
1099
|
var TIER_LIMITS = {
|
|
1100
|
+
// Every plan runs every check (pricing-tiers.json: free_audit / free_registered 280). Plans
|
|
1101
|
+
// differ in sites, schedules, pages per audit, PRs and alerts - not in what an audit checks.
|
|
1100
1102
|
free_anon: {
|
|
1101
|
-
checks:
|
|
1103
|
+
checks: 280,
|
|
1102
1104
|
sites: 0,
|
|
1103
1105
|
domains_per_month: 1,
|
|
1104
|
-
features: { geo:
|
|
1106
|
+
features: { geo: true, auto_fix: true, github: false, ai: false }
|
|
1105
1107
|
},
|
|
1106
1108
|
free: {
|
|
1107
|
-
checks:
|
|
1109
|
+
checks: 280,
|
|
1108
1110
|
sites: 1,
|
|
1109
1111
|
domains_per_month: 2,
|
|
1110
|
-
features: { geo:
|
|
1112
|
+
features: { geo: true, auto_fix: true, github: true, ai: false }
|
|
1111
1113
|
},
|
|
1112
1114
|
solo: {
|
|
1113
1115
|
checks: 280,
|
|
1114
1116
|
sites: 3,
|
|
1115
1117
|
domains_per_month: 5,
|
|
1116
|
-
features: { geo: true, auto_fix: true, github:
|
|
1118
|
+
features: { geo: true, auto_fix: true, github: true, ai: true }
|
|
1117
1119
|
},
|
|
1118
1120
|
pro: {
|
|
1119
1121
|
checks: 280,
|
|
@@ -1139,21 +1141,14 @@ var UPSELL_MESSAGES = {
|
|
|
1139
1141
|
free_audit_complete: () => [
|
|
1140
1142
|
"",
|
|
1141
1143
|
chalk3.yellow("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"),
|
|
1142
|
-
chalk3.yellow.bold(" \u{1F680}
|
|
1143
|
-
chalk3.dim("
|
|
1144
|
+
chalk3.yellow.bold(" \u{1F680} Keep this site audited, free"),
|
|
1145
|
+
chalk3.dim(" A free account audits one site weekly, keeps the history and"),
|
|
1146
|
+
chalk3.dim(" emails you a weekly report."),
|
|
1144
1147
|
"",
|
|
1145
1148
|
chalk3.cyan(` \u2192 rankcli login`),
|
|
1146
1149
|
chalk3.yellow("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"),
|
|
1147
1150
|
""
|
|
1148
1151
|
],
|
|
1149
|
-
// When checks limit is reached
|
|
1150
|
-
checks_limit: (ctx) => [
|
|
1151
|
-
"",
|
|
1152
|
-
chalk3.yellow(`\u26A0\uFE0F Running ${ctx.current || 50} of ${TIER_LIMITS.solo.checks} available checks`),
|
|
1153
|
-
chalk3.dim(` Unlock all ${TIER_LIMITS.solo.checks}+ checks with Solo ($9/mo)`),
|
|
1154
|
-
chalk3.cyan(` \u2192 ${WEB_APP_URL2}/pricing?from=cli_checks`),
|
|
1155
|
-
""
|
|
1156
|
-
],
|
|
1157
1152
|
// When domain limit is reached
|
|
1158
1153
|
domain_limit: (ctx) => [
|
|
1159
1154
|
"",
|
|
@@ -1166,18 +1161,6 @@ var UPSELL_MESSAGES = {
|
|
|
1166
1161
|
chalk3.red("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"),
|
|
1167
1162
|
""
|
|
1168
1163
|
],
|
|
1169
|
-
// When GEO features are limited
|
|
1170
|
-
geo_limited: (ctx) => [
|
|
1171
|
-
"",
|
|
1172
|
-
chalk3.yellow("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"),
|
|
1173
|
-
chalk3.yellow.bold(" \u{1F916} Full GEO analysis requires Solo"),
|
|
1174
|
-
chalk3.dim(" You're seeing basic AI crawler access checks."),
|
|
1175
|
-
chalk3.dim(" Full analysis includes: LLM signals, citation readiness, content structure"),
|
|
1176
|
-
"",
|
|
1177
|
-
chalk3.cyan(` \u2192 ${WEB_APP_URL2}/pricing?from=cli_geo`),
|
|
1178
|
-
chalk3.yellow("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"),
|
|
1179
|
-
""
|
|
1180
|
-
],
|
|
1181
1164
|
// When auto-fix is attempted without access
|
|
1182
1165
|
auto_fix_blocked: () => [
|
|
1183
1166
|
"",
|
|
@@ -1278,10 +1261,6 @@ function showUpsell(messageKey, context) {
|
|
|
1278
1261
|
const lines = messageFn(ctx);
|
|
1279
1262
|
lines.forEach((line) => console.log(line));
|
|
1280
1263
|
}
|
|
1281
|
-
function hasFeature(tier, feature) {
|
|
1282
|
-
const limits = TIER_LIMITS[tier];
|
|
1283
|
-
return limits?.features?.[feature] ?? false;
|
|
1284
|
-
}
|
|
1285
1264
|
|
|
1286
1265
|
// src/models.ts
|
|
1287
1266
|
var OPENAI_FAST = "gpt-5.6-luna";
|
|
@@ -1812,7 +1791,7 @@ async function audit(options) {
|
|
|
1812
1791
|
const tierId = tierFromPlanId(planId) ?? (loggedIn ? "free" : "free_anon");
|
|
1813
1792
|
const checksLimit = TIER_LIMITS[tierId].checks;
|
|
1814
1793
|
let premiumChecks;
|
|
1815
|
-
|
|
1794
|
+
{
|
|
1816
1795
|
const passphrase = getDecryptPassphrase();
|
|
1817
1796
|
if (passphrase) {
|
|
1818
1797
|
try {
|
|
@@ -2023,17 +2002,6 @@ async function audit(options) {
|
|
|
2023
2002
|
}
|
|
2024
2003
|
}
|
|
2025
2004
|
console.log("\n" + chalk4.bold("\u2550".repeat(60)));
|
|
2026
|
-
const isFreeTier = tierId === "free" || tierId === "free_anon";
|
|
2027
|
-
if (isFreeTier) {
|
|
2028
|
-
const checksRun = mergedIssues.length > 0 ? loggedIn ? 100 : 50 : 0;
|
|
2029
|
-
showUpsell("checks_limit", {
|
|
2030
|
-
tier: loggedIn ? "free" : "free_anon",
|
|
2031
|
-
current: checksRun
|
|
2032
|
-
});
|
|
2033
|
-
}
|
|
2034
|
-
if (options.geo && isFreeTier) {
|
|
2035
|
-
showUpsell("geo_limited", { tier: loggedIn ? "free" : "free_anon" });
|
|
2036
|
-
}
|
|
2037
2005
|
if (loggedIn) {
|
|
2038
2006
|
const syncSpinner = ora2("Syncing to cloud...").start();
|
|
2039
2007
|
const syncResult = await syncToCloud(url, primaryReport, mergedIssues, successCount, aiAnalysis, totalTime, actualChecksRun);
|
|
@@ -2152,14 +2120,6 @@ async function apply(options) {
|
|
|
2152
2120
|
}
|
|
2153
2121
|
console.log("\n\u{1F680} RankCLI - Apply Fixes");
|
|
2154
2122
|
console.log("\u2550".repeat(50));
|
|
2155
|
-
const loggedIn = isLoggedIn();
|
|
2156
|
-
const userInfo = getUserInfo();
|
|
2157
|
-
const tier = userInfo.planName?.toLowerCase() || "free";
|
|
2158
|
-
const hasAutoFix = loggedIn && hasFeature(tier, "auto_fix");
|
|
2159
|
-
if (!hasAutoFix) {
|
|
2160
|
-
showUpsell("auto_fix_blocked");
|
|
2161
|
-
return;
|
|
2162
|
-
}
|
|
2163
2123
|
console.log("\n\u{1F50D} Detecting framework...");
|
|
2164
2124
|
const frameworkResult = await detectFramework3({ cwd });
|
|
2165
2125
|
const framework = frameworkResult.success ? frameworkResult.data : { name: "Unknown", metaPattern: "html-head" };
|
|
@@ -2420,16 +2380,6 @@ async function runFix(options) {
|
|
|
2420
2380
|
if (loggedIn) await ensureApiKeyPlan();
|
|
2421
2381
|
const userInfo = getUserInfo();
|
|
2422
2382
|
const tier = tierFromPlanId(userInfo.planId) ?? tierFromPlanId(userInfo.planName) ?? "free";
|
|
2423
|
-
const hasAutoFix = loggedIn && hasFeature(tier, "auto_fix");
|
|
2424
|
-
if (!options.dryRun && !hasAutoFix) {
|
|
2425
|
-
if (options.output !== "json") {
|
|
2426
|
-
showUpsell("auto_fix_blocked");
|
|
2427
|
-
}
|
|
2428
|
-
return {
|
|
2429
|
-
success: false,
|
|
2430
|
-
error: "Auto-fix requires Solo tier or higher. Please upgrade at " + WEB_APP_URL + "/account"
|
|
2431
|
-
};
|
|
2432
|
-
}
|
|
2433
2383
|
if (options.output !== "json") {
|
|
2434
2384
|
console.log("\n\u{1F527} RankCLI Fix - Agentic SEO Fixer");
|
|
2435
2385
|
console.log("\u2550".repeat(50));
|
|
@@ -3773,7 +3723,7 @@ async function alerts(options) {
|
|
|
3773
3723
|
if (options.list) {
|
|
3774
3724
|
console.log("\u{1F4CB} Current alert configurations:\n");
|
|
3775
3725
|
console.log(" (Alert configs are stored in your RankCLI account)");
|
|
3776
|
-
console.log(" Run `rankcli
|
|
3726
|
+
console.log(" Run `rankcli login` first, then manage alerts at https://rankcli.dev/account?tab=notifications\n");
|
|
3777
3727
|
rl.close();
|
|
3778
3728
|
return;
|
|
3779
3729
|
}
|
|
@@ -3848,8 +3798,8 @@ async function alerts(options) {
|
|
|
3848
3798
|
}
|
|
3849
3799
|
console.log("");
|
|
3850
3800
|
console.log("To save this configuration:");
|
|
3851
|
-
console.log("1. Log in with `rankcli
|
|
3852
|
-
console.log("2. Add alert config at https://rankcli.dev/account
|
|
3801
|
+
console.log("1. Log in with `rankcli login`");
|
|
3802
|
+
console.log("2. Add alert config at https://rankcli.dev/account?tab=notifications");
|
|
3853
3803
|
console.log("");
|
|
3854
3804
|
console.log("Or use the API:");
|
|
3855
3805
|
console.log(` POST /api/alerts with webhook_url and settings`);
|
|
@@ -3908,7 +3858,7 @@ async function testWebhook(channel, webhookUrl) {
|
|
|
3908
3858
|
}
|
|
3909
3859
|
|
|
3910
3860
|
// src/version.ts
|
|
3911
|
-
var VERSION = "0.0.
|
|
3861
|
+
var VERSION = "0.0.31";
|
|
3912
3862
|
|
|
3913
3863
|
// src/index.ts
|
|
3914
3864
|
var program = new Command();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rankcli/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.31",
|
|
4
4
|
"description": "RankCLI - Ship code, get ranked. SEO meets CI/CD.",
|
|
5
5
|
"homepage": "https://rankcli.dev",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"update-version": "node scripts/update-version.js"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@rankcli/agent-runtime": "^0.0.
|
|
48
|
+
"@rankcli/agent-runtime": "^0.0.22",
|
|
49
49
|
"@supabase/supabase-js": "^2.98.0",
|
|
50
50
|
"chalk": "^5.3.0",
|
|
51
51
|
"commander": "^12.0.0",
|