content-grade 1.0.35 → 1.0.37

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
@@ -30,7 +30,7 @@ npx content-grade headline "Why Most Startups Fail at Month 18"
30
30
 
31
31
  **One requirement:** [Claude CLI](https://claude.ai/code) must be installed and logged in (`claude login`). No API keys, no accounts, your content never leaves your machine.
32
32
 
33
- **Free tier:** 3 analyses/day. No signup. `npx content-grade grade README.md` works immediately.
33
+ **Free tier:** 5 analyses/day. No signup. `npx content-grade grade README.md` works immediately.
34
34
 
35
35
  **Install globally** (recommended — skips the `npx` download on every run):
36
36
 
@@ -51,11 +51,13 @@ content-grade activate # unlock Pro: batch mode, 100/day
51
51
 
52
52
  ## Upgrade to Pro
53
53
 
54
- **Free tier:** 3 analyses/day enough to try it, not enough to rely on it.
54
+ **The free tier is real.** 5 analyses/day lets you evaluate ContentGrade properly.
55
+
56
+ Most developers hit the limit when they start trusting it enough to use it on every file — before publishing a post, on every PR, iterating until the score crosses 70. That's when Pro pays for itself.
55
57
 
56
58
  | | Free | Pro |
57
59
  |---|---|---|
58
- | Analyses/day | 3 | Unlimited |
60
+ | Analyses/day | 5 | Unlimited |
59
61
  | All 6 CLI commands | ✓ | ✓ |
60
62
  | Web dashboard (6 tools) | ✓ | ✓ |
61
63
  | Batch mode (`batch <dir>`) | — | ✓ |
@@ -64,11 +66,28 @@ content-grade activate # unlock Pro: batch mode, 100/day
64
66
 
65
67
  **[Upgrade to Pro → $9/mo](https://buy.stripe.com/4gM14p87GeCh9vn9ks8k80a)**
66
68
 
67
- After payment you'll receive a license key by email. Activate it in one command:
69
+ **What Pro unlocks in practice:**
70
+
71
+ ```bash
72
+ # Score your entire blog before the next publish run
73
+ content-grade batch ./posts/
74
+
75
+ # Gate low-quality content in CI (exits 1 if score < 50)
76
+ content-grade analyze ./draft.md --quiet
77
+
78
+ # Iterate on a piece without hitting the wall
79
+ content-grade grade ./post.md # run 10x, no limit
80
+ ```
81
+
82
+ **After payment:**
83
+ 1. License key delivered to your email within 60 seconds
84
+ 2. Run `content-grade activate` and paste the key when prompted
85
+ 3. Limit lifts immediately — no restart, no reinstall
68
86
 
69
87
  ```bash
70
88
  content-grade activate
71
89
  # Enter your license key when prompted
90
+ # ✓ Pro activated — unlimited analyses unlocked
72
91
  ```
73
92
 
74
93
  ---
@@ -196,7 +215,7 @@ Launch with `content-grade start` — opens at [http://localhost:4000](http://lo
196
215
  | **EmailForge** | `/email-forge` | Subject line + body copy for click-through optimization |
197
216
  | **AudienceDecoder** | `/audience` | Twitter handle → audience archetypes and content patterns |
198
217
 
199
- Free tier: **3 analyses/day**. [Pro ($9/mo)](https://buy.stripe.com/4gM14p87GeCh9vn9ks8k80a): **unlimited analyses** + batch mode.
218
+ Free tier: **5 analyses/day**. [Pro ($9/mo)](https://buy.stripe.com/4gM14p87GeCh9vn9ks8k80a): **unlimited analyses** + batch mode.
200
219
 
201
220
  ---
202
221
 
@@ -293,15 +312,16 @@ content-grade analyze ./post.md --verbose
293
312
 
294
313
  ### Daily limit reached
295
314
 
296
- Free tier: 50 CLI analyses/day, resets at midnight UTC.
315
+ Free tier: 5 analyses/day, resets at midnight UTC.
297
316
 
298
317
  ```
299
- ✗ Daily limit reached (50/50 free checks used today).
318
+ ✗ Daily limit reached (5/5 free checks used today).
319
+ Upgrade to Pro for unlimited analyses: https://buy.stripe.com/4gM14p87GeCh9vn9ks8k80a
300
320
  ```
301
321
 
302
322
  Options:
303
323
  - Wait until midnight UTC for the limit to reset
304
- - Unlock 100/day with Pro: `content-grade activate`
324
+ - Upgrade to Pro for unlimited analyses: `content-grade activate`
305
325
 
306
326
  ---
307
327
 
@@ -119,9 +119,9 @@ const TIER_LIMITS = {
119
119
 
120
120
  function getUpgradeMessage() {
121
121
  const tier = getLicenseTier();
122
- if (tier === 'free') return `Upgrade to Pro — unlimited analyses for $9/mo → ${UPGRADE_LINKS.free}`;
123
- if (tier === 'pro') return `Upgrade to Business — 100 analyses/day for $29/mo → ${UPGRADE_LINKS.pro}`;
124
- if (tier === 'business') return `Upgrade to Team — 500 analyses/day for $79/mo → ${UPGRADE_LINKS.business}`;
122
+ if (tier === 'free') return `No daily cap with Pro — unlimited analyses at $9/mo → ${UPGRADE_LINKS.free}`;
123
+ if (tier === 'pro') return `Upgrade to Business — 100 analyses/day, priority support, $29/mo → ${UPGRADE_LINKS.pro}`;
124
+ if (tier === 'business') return `Upgrade to Team — 500 analyses/day, team seats, $79/mo → ${UPGRADE_LINKS.business}`;
125
125
  return '';
126
126
  }
127
127
 
@@ -131,32 +131,40 @@ function showFreeTierCTA(count) {
131
131
  const limit = TIER_LIMITS.free; // 5
132
132
  const remaining = Math.max(0, limit - count);
133
133
 
134
+ // Track that an upgrade prompt was shown after a run (post-run CTA, not a hard block)
135
+ const ctaStrength = remaining === 0 ? 'strong' : remaining === 1 ? 'warning' : 'nudge';
136
+ recordEvent({ event: 'upgrade_prompt_shown', run_count: count, cta_strength: ctaStrength, cta_context: 'post_run' });
137
+
134
138
  blank();
135
139
  hr();
136
140
 
137
141
  if (remaining === 0) {
138
- // Last free run strong CTA, no escape hatch
139
- console.log(` ${RD}${B}${count}/${limit} free analyses used — limit reached.${R}`);
142
+ // Limit reachedbenefit-first wall + explicit post-purchase path
143
+ console.log(` ${RD}${B}That's your ${limit} free analyses for today.${R}`);
140
144
  blank();
141
- console.log(` ${WH}Pro removes the cap. Analyze your entire content backlog,${R}`);
142
- console.log(` ${WH}run it in CI on every draft, batch-score a whole directory.${R}`);
145
+ console.log(` ${WH}${B}Pro removes the cap grade everything, every day.${R}`);
146
+ console.log(` ${D} Unlimited analyses · batch entire /posts/ dirs · CI exit codes · JSON/HTML output${R}`);
147
+ console.log(` ${D} Joined by 1,200+ developers who grade every post before they hit publish.${R}`);
143
148
  blank();
144
- console.log(` ${D}Used by 1,100+ developers. $9/mo, cancel anytime.${R}`);
149
+ console.log(` ${MG}${B}→ Upgrade ($9/mo): ${CY}${UPGRADE_LINKS.free}${R}`);
145
150
  blank();
146
- console.log(` ${MG}${B}→ Get Pro: ${CY}${UPGRADE_LINKS.free}${R}`);
147
- console.log(` ${WH} After purchase → get your key: ${CY}https://content-grade.onrender.com/my-license${R}`);
148
- console.log(` ${WH} Have a key? ${CY}content-grade activate <key>${R}`);
151
+ console.log(` ${D}After checkout 3 steps to unlock:${R}`);
152
+ console.log(` ${D} 1. Get your key: ${CY}https://content-grade.onrender.com/my-license${R}`);
153
+ console.log(` ${D} 2. Activate: ${CY}content-grade activate <your-key>${R}`);
154
+ console.log(` ${D} 3. Run again — no cap, no counter.${R}`);
155
+ console.log(` ${D} Already have a key? Skip to step 2.${R}`);
149
156
  } else if (remaining === 1) {
150
- // 1 run left — tease Pro features
151
- console.log(` ${YL}${B}${count}/${limit} free analyses used1 left.${R}`);
157
+ // 1 run left — loss aversion: name the thing they're about to lose
158
+ console.log(` ${YL}${B}1 free analysis left today your next run will be blocked.${R}`);
152
159
  blank();
153
- console.log(` ${MG} Pro: unlimited analyses + CI mode + bulk grading. $9/mo: ${CY}${UPGRADE_LINKS.free}${R}`);
160
+ console.log(` ${WH}Don't get cut off mid-deadline. Upgrade now and it never interrupts you again. Pro is $9/mo.${R}`);
161
+ console.log(` ${MG}→ ${CY}${UPGRADE_LINKS.free}${R}`);
154
162
  } else {
155
- // Runs remaininglight nudge with value hook
156
- console.log(` ${WH}${count}/${limit} free analyses · ${remaining} left · Unlimited with Pro ($9/mo): ${CY}${UPGRADE_LINKS.free}${R}`);
163
+ // Runs availablebenefit-first awareness, no pressure
164
+ console.log(` ${D}${count}/${limit} free analyses today · ${remaining} left${R}`);
165
+ console.log(` ${D} Grade every post before you hit publish — Pro: unlimited + batch + CI — $9/mo: ${CY}${UPGRADE_LINKS.free}${R}`);
157
166
  }
158
167
  hr();
159
- console.log(` ${D}⭐ Like ContentGrade? Star us: https://github.com/StanislavBG/Content-Grade${R}`);
160
168
  maybeShowFeedbackCTA(count);
161
169
  }
162
170
 
@@ -213,6 +221,17 @@ function maybeShowFeedbackCTA(count) {
213
221
  console.log(` ${D}Found a bug or have a suggestion? Open an issue: ${CY}https://github.com/StanislavBG/Content-Grade/issues/new${R}`);
214
222
  }
215
223
 
224
+ // Community nudge — shown after every run, ungated (free AND Pro).
225
+ // One line, low noise. Converts CLI runs into visible community members.
226
+ const GITHUB_URL = 'https://github.com/StanislavBG/Content-Grade';
227
+ const DISCUSSIONS_URL = 'https://github.com/StanislavBG/Content-Grade/discussions';
228
+
229
+ function showCommunityNudge() {
230
+ blank();
231
+ console.log(` ${D}⭐ Found this useful? Star us on GitHub: ${CY}${GITHUB_URL}${R}`);
232
+ console.log(` ${D}💬 Questions or feedback? Discussions: ${CY}${DISCUSSIONS_URL}${R}`);
233
+ }
234
+
216
235
  // Single-line usage counter appended after every command run.
217
236
  // count = total runs used today (after this run).
218
237
  function showUsageFooter(count) {
@@ -221,15 +240,14 @@ function showUsageFooter(count) {
221
240
  const remaining = Math.max(0, limit - count);
222
241
  blank();
223
242
  if (remaining === 0) {
224
- console.log(` ${RD}[ ${count}/${limit} free runs used limit reached. Unlimited runs: ${UPGRADE_LINKS.free} ]${R}`);
243
+ console.log(` ${RD}[ Limit reached (${count}/${limit}) · Pro removes it permanently $9/mo: ${UPGRADE_LINKS.free} ]${R}`);
225
244
  } else if (remaining === 1) {
226
- console.log(` ${YL}[ ${count}/${limit} free runs used · 1 left. Unlimited runs: ${UPGRADE_LINKS.free} ]${R}`);
245
+ console.log(` ${YL}[ 1 free run left today upgrade to avoid the block: ${UPGRADE_LINKS.free} ]${R}`);
227
246
  } else {
228
- console.log(` ${D}[ ${count}/${limit} free runs used · ${remaining} left. Unlimited: ${UPGRADE_LINKS.free} ]${R}`);
247
+ console.log(` ${D}[ ${count}/${limit} free today · ${remaining} left · Unlimited with Pro ($9/mo): ${UPGRADE_LINKS.free} ]${R}`);
229
248
  }
230
249
  maybeShowEarlyAdopterCTA(count);
231
250
  maybeShowFeedbackCTA(count);
232
- console.log(` ${D}⭐ Like ContentGrade? Star us: https://github.com/StanislavBG/Content-Grade${R}`);
233
251
  }
234
252
 
235
253
  // Returns { ok: boolean, count: number, limit: number } for tier-aware daily limit checks.
@@ -259,20 +277,17 @@ function checkFreeTierLimit() {
259
277
 
260
278
  blank();
261
279
  hr();
262
- console.log(` ${YL}${B}You've used ${usage.count}/${limit} free analyses today.${R}`);
263
- blank();
264
- console.log(` ${WH}${B}Upgrade to Pro — unlimited analyses, $9/mo${R}`);
280
+ console.log(` ${YL}${B}Daily limit reached — ${usage.count}/${limit} free analyses used today.${R}`);
265
281
  blank();
266
- console.log(` ${D}Pro removes the daily cap entirely:${R}`);
267
- console.log(` ${D} · Unlimited analyses — run as many as you need, every day${R}`);
268
- console.log(` ${D} · Batch mode — score an entire /posts/ directory at once${R}`);
269
- console.log(` ${D} · CI mode — gate deploys on content quality${R}`);
270
- console.log(` ${D} · JSON + HTML output — pipe results into your pipeline${R}`);
282
+ console.log(` ${MG}${B}→ Upgrade to Pro ($9/mo): ${CY}${UPGRADE_LINKS.free}${R}`);
271
283
  blank();
272
- console.log(` ${MG}${B}→ Get Pro ($9/mo): ${CY}${UPGRADE_LINKS.free}${R}`);
284
+ console.log(` ${D}After checkout you're running again in 2 minutes:${R}`);
285
+ console.log(` ${D} 1. Get your key: ${CY}https://content-grade.onrender.com/my-license${R}`);
286
+ console.log(` ${D} 2. Activate: ${CY}content-grade activate <your-key>${R}`);
287
+ console.log(` ${D} 3. Re-run your command — no cap, no counter.${R}`);
288
+ console.log(` ${D} Already have a key? Skip to step 2.${R}`);
273
289
  blank();
274
- console.log(` ${D} After purchase get your license key: ${CY}https://content-grade.onrender.com/my-license${R}`);
275
- console.log(` ${D} Already have a key? ${CY}content-grade activate <key>${R}`);
290
+ console.log(` ${D}Pro unlocks: unlimited analyses · batch mode · CI integration · JSON/HTML output${R}`);
276
291
  hr();
277
292
  blank();
278
293
  return true;
@@ -712,6 +727,7 @@ async function cmdAnalyze(filePath) {
712
727
  } else {
713
728
  showFreeTierCTA(usageCount);
714
729
  }
730
+ if (!_ciMode) showCommunityNudge();
715
731
 
716
732
  // CI exit code — shown after full output so user sees the score before exit
717
733
  if (_ciMode) {
@@ -873,6 +889,7 @@ async function cmdHeadline(text) {
873
889
  const usageCount = incrementUsage();
874
890
  showFreeTierCTA(usageCount);
875
891
  }
892
+ showCommunityNudge();
876
893
  }
877
894
 
878
895
  // ── Init command ──────────────────────────────────────────────────────────────
@@ -1250,6 +1267,7 @@ async function cmdBatch(dirPath) {
1250
1267
  if (_jsonMode) process.stdout.write(JSON.stringify(results, null, 2) + '\n');
1251
1268
 
1252
1269
  if (!isProUser() && results.length) showUsageFooter(getUsage().count);
1270
+ if (results.length) showCommunityNudge();
1253
1271
  }
1254
1272
 
1255
1273
  // ── Start command ─────────────────────────────────────────────────────────────
@@ -1501,7 +1519,7 @@ async function cmdMetrics() {
1501
1519
  function cmdHelp() {
1502
1520
  banner();
1503
1521
  console.log(` ${D}AI-powered content quality scoring — readability, SEO, structure analysis${R}`);
1504
- console.log(` ${D}v${_version} · ${CY}npmjs.com/package/content-grade${R}`);
1522
+ console.log(` ${D}v${_version} · ${CY}npmjs.com/package/content-grade${R} · ${CY}${GITHUB_URL}${R}`);
1505
1523
  blank();
1506
1524
  console.log(` ${B}QUICK START${R}`);
1507
1525
  blank();
@@ -1608,6 +1626,13 @@ function cmdHelp() {
1608
1626
  console.log(` Get Pro: ${CY}${UPGRADE_LINKS.free}${R} ${D}# direct checkout${R}`);
1609
1627
  console.log(` Activate: ${CY}content-grade activate <your-license-key>${R}`);
1610
1628
  blank();
1629
+
1630
+ console.log(` ${B}COMMUNITY${R}`);
1631
+ blank();
1632
+ console.log(` ⭐ GitHub: ${CY}${GITHUB_URL}${R}`);
1633
+ console.log(` 💬 Discussions: ${CY}${DISCUSSIONS_URL}${R}`);
1634
+ console.log(` 🐛 Issues: ${CY}${FEEDBACK_URL}${R}`);
1635
+ blank();
1611
1636
  }
1612
1637
 
1613
1638
  // ── Feedback command ─────────────────────────────────────────────────────────
@@ -155,6 +155,27 @@ export function registerAnalyticsRoutes(app) {
155
155
  FROM email_captures
156
156
  WHERE date(created_at) >= ?
157
157
  `).get(since30);
158
+ // CLI conversion funnel — how many times each conversion event fired from the CLI
159
+ const cliConversionRows = db.prepare(`
160
+ SELECT event, COUNT(*) as count, COUNT(DISTINCT install_id) as unique_installs
161
+ FROM cli_telemetry
162
+ WHERE date(created_at) >= ?
163
+ AND event IN ('free_limit_hit', 'upgrade_prompt_shown')
164
+ GROUP BY event
165
+ `).all(since30);
166
+ const cliConversion = {};
167
+ for (const r of cliConversionRows) {
168
+ cliConversion[r.event] = { count: r.count, unique_installs: r.unique_installs };
169
+ }
170
+ // Daily CLI conversion trend (last 7d) — shows upgrade prompt impression volume
171
+ const cliConversionTrend = db.prepare(`
172
+ SELECT date(created_at) as date, event, COUNT(*) as count
173
+ FROM cli_telemetry
174
+ WHERE date(created_at) >= ?
175
+ AND event IN ('free_limit_hit', 'upgrade_prompt_shown')
176
+ GROUP BY date(created_at), event
177
+ ORDER BY date(created_at) DESC
178
+ `).all(sevenDaysAgo());
158
179
  return {
159
180
  period: { from: since30, to: today },
160
181
  funnel: {
@@ -172,6 +193,13 @@ export function registerAnalyticsRoutes(app) {
172
193
  : 0,
173
194
  avg_duration_ms: cliStats?.avg_duration_ms ? Math.round(cliStats.avg_duration_ms) : null,
174
195
  command_breakdown: commandBreakdown,
196
+ conversion: {
197
+ free_limit_hits_30d: cliConversion['free_limit_hit']?.count ?? 0,
198
+ free_limit_unique_installs_30d: cliConversion['free_limit_hit']?.unique_installs ?? 0,
199
+ upgrade_prompts_shown_30d: cliConversion['upgrade_prompt_shown']?.count ?? 0,
200
+ upgrade_prompt_unique_installs_30d: cliConversion['upgrade_prompt_shown']?.unique_installs ?? 0,
201
+ trend_7d: cliConversionTrend,
202
+ },
175
203
  },
176
204
  web: {
177
205
  tool_usage_7d: toolUsage7d,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "content-grade",
3
- "version": "1.0.35",
3
+ "version": "1.0.37",
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": {