@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 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: paid-plan checks + dashboard sync
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 Solo+ key, opens auto-fix PRs).
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 Checks | 100 | 280+ |
282
- | GEO Analysis | Basic | Full |
283
- | Framework Fixes | - | ✅ 25+ |
284
- | Auto-Fix PRs | - | ✅ |
285
- | 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).
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 || process.env.VITE_SUPABASE_URL || INJECTED_CONFIG?.supabaseUrl;
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/cli-setup"
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 || process.env.VITE_SUPABASE_ANON_KEY || INJECTED_CONFIG?.supabaseAnonKey;
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/cli-setup"
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: 50,
1116
+ checks: 280,
1115
1117
  sites: 0,
1116
1118
  domains_per_month: 1,
1117
- features: { geo: false, auto_fix: false, github: false, ai: false }
1119
+ features: { geo: true, auto_fix: true, github: false, ai: false }
1118
1120
  },
1119
1121
  free: {
1120
- checks: 100,
1122
+ checks: 280,
1121
1123
  sites: 1,
1122
1124
  domains_per_month: 2,
1123
- features: { geo: "basic", auto_fix: false, github: false, ai: false }
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: false, ai: true }
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} Get 2x more checks + audit history"),
1156
- import_chalk3.default.dim(" Create a free account to unlock 100 checks and save your results."),
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
- if (checksLimit > TIER_LIMITS.free.checks) {
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 auth login` first, then manage alerts at https://rankcli.dev/account/alerts\n");
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 auth login`");
3996
- console.log("2. Add alert config at https://rankcli.dev/account/alerts");
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.30";
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 || process.env.VITE_SUPABASE_URL || INJECTED_CONFIG?.supabaseUrl;
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/cli-setup"
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 || process.env.VITE_SUPABASE_ANON_KEY || INJECTED_CONFIG?.supabaseAnonKey;
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/cli-setup"
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: 50,
1103
+ checks: 280,
1102
1104
  sites: 0,
1103
1105
  domains_per_month: 1,
1104
- features: { geo: false, auto_fix: false, github: false, ai: false }
1106
+ features: { geo: true, auto_fix: true, github: false, ai: false }
1105
1107
  },
1106
1108
  free: {
1107
- checks: 100,
1109
+ checks: 280,
1108
1110
  sites: 1,
1109
1111
  domains_per_month: 2,
1110
- features: { geo: "basic", auto_fix: false, github: false, ai: false }
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: false, ai: true }
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} Get 2x more checks + audit history"),
1143
- chalk3.dim(" Create a free account to unlock 100 checks and save your results."),
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
- if (checksLimit > TIER_LIMITS.free.checks) {
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 auth login` first, then manage alerts at https://rankcli.dev/account/alerts\n");
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 auth login`");
3852
- console.log("2. Add alert config at https://rankcli.dev/account/alerts");
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.30";
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.30",
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.21",
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",