content-grade 1.0.14 → 1.0.15

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.
@@ -46,6 +46,11 @@ function getLicenseKey() {
46
46
  return process.env.CONTENT_GRADE_KEY || loadConfig().licenseKey || null;
47
47
  }
48
48
 
49
+ function getLicenseTier() {
50
+ const cfg = loadConfig();
51
+ return cfg.tier || 'free'; // free | starter | pro | team
52
+ }
53
+
49
54
  function isProUser() { return Boolean(getLicenseKey()); }
50
55
 
51
56
  function getTodayKey() { return new Date().toISOString().slice(0, 10); }
@@ -66,13 +71,45 @@ function incrementUsage() {
66
71
  return u.count;
67
72
  }
68
73
 
69
- const FREE_DAILY_LIMIT = 5;
74
+ // Usage tiers — daily limits per plan
75
+ const TIER_LIMITS = {
76
+ free: 5, // 5/day
77
+ starter: 20, // ~600/mo ≈ 50/mo was too low for daily use
78
+ pro: 50, // ~1500/mo
79
+ team: 100, // hard cap even for top tier — no abuse
80
+ };
81
+
82
+ const UPGRADE_LINKS = {
83
+ free: 'https://buy.stripe.com/eVq6oJbjSdyd6jbaow8k805', // Starter $9/mo
84
+ starter: 'https://buy.stripe.com/00w9AV87G65L7nf54c8k806', // Pro $29/mo
85
+ pro: 'https://buy.stripe.com/4gM28t73C79P0YR7ck8k807', // Team $79/mo
86
+ };
87
+
88
+ const TIER_NAMES = {
89
+ free: 'Free (5/day)',
90
+ starter: 'Starter — $9/mo (20/day)',
91
+ pro: 'Pro — $29/mo (50/day)',
92
+ team: 'Team — $79/mo (100/day)',
93
+ };
94
+
95
+ function getDailyLimit() {
96
+ const tier = getLicenseTier();
97
+ return TIER_LIMITS[tier] || TIER_LIMITS.free;
98
+ }
70
99
 
71
100
  function checkDailyLimit() {
72
- if (isProUser()) return { ok: true };
101
+ const limit = getDailyLimit();
73
102
  const u = getUsage();
74
- if (u.count >= FREE_DAILY_LIMIT) return { ok: false, count: u.count, limit: FREE_DAILY_LIMIT };
75
- return { ok: true, count: u.count, limit: FREE_DAILY_LIMIT };
103
+ if (u.count >= limit) return { ok: false, count: u.count, limit };
104
+ return { ok: true, count: u.count, limit };
105
+ }
106
+
107
+ function getUpgradeMessage() {
108
+ const tier = getLicenseTier();
109
+ const link = UPGRADE_LINKS[tier];
110
+ if (!link) return ''; // team tier — no upgrade available
111
+ const nextTier = tier === 'free' ? 'Starter ($9/mo, 20/day)' : tier === 'starter' ? 'Pro ($29/mo, 50/day)' : 'Team ($79/mo, 100/day)';
112
+ return `Upgrade to ${nextTier} → ${link}`;
76
113
  }
77
114
 
78
115
  let _version = '1.0.0';
@@ -344,13 +381,13 @@ async function cmdAnalyze(filePath) {
344
381
  const limitCheck = checkDailyLimit();
345
382
  if (!limitCheck.ok) {
346
383
  blank();
347
- fail(`Daily limit reached (${limitCheck.count}/${limitCheck.limit} free checks used today).`);
384
+ fail(`Daily limit reached (${limitCheck.count}/${limitCheck.limit} runs used today on ${TIER_NAMES[getLicenseTier()]} plan).`);
348
385
  blank();
349
386
  console.log(` ${B}Options:${R}`);
350
387
  console.log(` ${D}· Wait until tomorrow (limit resets at midnight)${R}`);
351
- console.log(` ${D}· Unlock unlimited: ${CY}content-grade activate${R}`);
388
+ console.log(` ${D}· Upgrade your plan: ${CY}content-grade activate${R}`);
352
389
  blank();
353
- console.log(` ${MG}Upgrade to Pro ($9/mo) for unlimited analyses →${R} ${CY}https://buy.stripe.com/5kQeVfew48dT7nf2W48k801${R}`);
390
+ console.log(` ${MG}${getUpgradeMessage()}${R}`);
354
391
  blank();
355
392
  process.exit(1);
356
393
  }
@@ -529,9 +566,9 @@ async function cmdAnalyze(filePath) {
529
566
  console.log(` ${CY}content-grade analyze https://yoursite.com/post${R} ${D}# audit any live URL${R}`);
530
567
  blank();
531
568
  if (remaining <= 10) {
532
- console.log(` ${YL}${remaining} free checks left today.${R} Unlock unlimited: ${CY}content-grade activate${R}`);
569
+ console.log(` ${YL}${remaining} runs left today (${TIER_NAMES[getLicenseTier()]}).${R} ${MG}${getUpgradeMessage()}${R}`);
533
570
  } else {
534
- console.log(` ${D}${remaining} free checks left today · Pro ($9/mo): ${CY}content-grade.github.io/Content-Grade${R}`);
571
+ console.log(` ${D}${remaining} runs left today. ${getUpgradeMessage()}${R}`);
535
572
  }
536
573
  }
537
574
 
@@ -609,13 +646,13 @@ async function cmdHeadline(text) {
609
646
  const limitCheck = checkDailyLimit();
610
647
  if (!limitCheck.ok) {
611
648
  blank();
612
- fail(`Daily limit reached (${limitCheck.count}/${limitCheck.limit} free checks used today).`);
649
+ fail(`Daily limit reached (${limitCheck.count}/${limitCheck.limit} runs used today on ${TIER_NAMES[getLicenseTier()]} plan).`);
613
650
  blank();
614
651
  console.log(` ${B}Options:${R}`);
615
652
  console.log(` ${D}· Wait until tomorrow (limit resets at midnight)${R}`);
616
- console.log(` ${D}· Unlock unlimited: ${CY}content-grade activate${R}`);
653
+ console.log(` ${D}· Upgrade your plan: ${CY}content-grade activate${R}`);
617
654
  blank();
618
- console.log(` ${MG}Upgrade to Pro ($9/mo) for unlimited analyses →${R} ${CY}https://buy.stripe.com/5kQeVfew48dT7nf2W48k801${R}`);
655
+ console.log(` ${MG}${getUpgradeMessage()}${R}`);
619
656
  blank();
620
657
  process.exit(1);
621
658
  }
@@ -705,7 +742,7 @@ async function cmdHeadline(text) {
705
742
  console.log(` ${D}Compare two headlines: ${CY}content-grade start${R} → HeadlineGrader compare${R}`);
706
743
  blank();
707
744
  if (!isProUser()) {
708
- console.log(` ${MG}Upgrade to Pro ($9/mo) for unlimited analyses →${R} ${CY}https://buy.stripe.com/5kQeVfew48dT7nf2W48k801${R}`);
745
+ console.log(` ${MG}${getUpgradeMessage()}${R}`);
709
746
  blank();
710
747
  }
711
748
  }
package/bin/telemetry.js CHANGED
@@ -20,7 +20,7 @@ const EVENTS_FILE = join(CONFIG_DIR, 'events.jsonl');
20
20
  // Telemetry endpoint: CLI events are forwarded here when telemetry is enabled.
21
21
  // Set CONTENT_GRADE_TELEMETRY_URL to enable remote aggregation (e.g. self-hosted endpoint).
22
22
  // Default: local-only (events stored at ~/.content-grade/events.jsonl, no remote send).
23
- const REMOTE_URL = process.env.CONTENT_GRADE_TELEMETRY_URL || '';
23
+ const REMOTE_URL = process.env.CONTENT_GRADE_TELEMETRY_URL || 'https://cg-telemetry.onrender.com/api/telemetry/events';
24
24
 
25
25
  // ── Internal helpers ──────────────────────────────────────────────────────────
26
26
 
@@ -72,15 +72,16 @@ export function initTelemetry() {
72
72
  return { installId: cfg.installId, isNew: false, optedOut: false };
73
73
  }
74
74
 
75
- // First run — generate anonymous install ID, opt-IN by default (off until user enables)
75
+ // First run — generate anonymous install ID, opt-in by default (like Next.js, Astro)
76
+ // Users can opt out: content-grade telemetry off, --no-telemetry, or CONTENT_GRADE_NO_TELEMETRY=1
76
77
  const installId = generateId();
77
78
  saveConfig({
78
79
  installId,
79
80
  installedAt: new Date().toISOString(),
80
- telemetryEnabled: false,
81
+ telemetryEnabled: true,
81
82
  });
82
83
 
83
- return { installId, isNew: true, optedOut: true };
84
+ return { installId, isNew: true, optedOut: false };
84
85
  }
85
86
 
86
87
  /**
@@ -106,6 +107,7 @@ export function recordEvent(data) {
106
107
 
107
108
  const event = {
108
109
  ...data,
110
+ package: 'content-grade',
109
111
  installId,
110
112
  timestamp: new Date().toISOString(),
111
113
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "content-grade",
3
- "version": "1.0.14",
3
+ "version": "1.0.15",
4
4
  "description": "AI-powered content analysis CLI. Score any blog post, landing page, or ad copy in under 30 seconds — runs on Claude CLI, no API key needed.",
5
5
  "type": "module",
6
6
  "bin": {