content-grade 1.0.46 → 1.0.48
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/bin/content-grade.js +46 -77
- package/dist/landing.html +56 -38
- package/dist-server/server/routes/analytics.js +23 -0
- package/package.json +1 -1
package/bin/content-grade.js
CHANGED
|
@@ -79,25 +79,26 @@ function getLicenseTier() {
|
|
|
79
79
|
function isProUser() { return Boolean(getLicenseKey()); }
|
|
80
80
|
|
|
81
81
|
function getUsage() {
|
|
82
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
82
83
|
try {
|
|
83
84
|
const d = JSON.parse(readFileSync(USAGE_FILE, 'utf8'));
|
|
84
|
-
//
|
|
85
|
-
if (d.date) return {
|
|
86
|
-
return {
|
|
87
|
-
} catch { return {
|
|
85
|
+
// Daily reset: if stored date differs from today, start fresh
|
|
86
|
+
if (d.date !== today) return { daily: 0, date: today };
|
|
87
|
+
return { daily: d.daily || 0, date: today };
|
|
88
|
+
} catch { return { daily: 0, date: today }; }
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
function incrementUsage() {
|
|
91
92
|
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
92
93
|
const u = getUsage();
|
|
93
|
-
u.
|
|
94
|
+
u.daily = (u.daily || 0) + 1;
|
|
94
95
|
writeFileSync(USAGE_FILE, JSON.stringify(u, null, 2), 'utf8');
|
|
95
|
-
return u.
|
|
96
|
+
return u.daily;
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
// Upgrade links — Free → Pro → Business → Team
|
|
99
100
|
const UPGRADE_LINKS = {
|
|
100
|
-
free: 'https://buy.stripe.com/4gM14p87GeCh9vn9ks8k80a', // Pro $
|
|
101
|
+
free: 'https://buy.stripe.com/4gM14p87GeCh9vn9ks8k80a', // Pro $19/mo — direct checkout
|
|
101
102
|
pro: 'https://buy.stripe.com/bJefZjafO2Tz36Z2W48k80b', // Business $29/mo
|
|
102
103
|
business: 'https://buy.stripe.com/cNiaEZfA8cu9bDv4088k80c', // Team $79/mo
|
|
103
104
|
};
|
|
@@ -110,7 +111,7 @@ const TIER_NAMES = {
|
|
|
110
111
|
};
|
|
111
112
|
|
|
112
113
|
const TIER_LIMITS = {
|
|
113
|
-
free:
|
|
114
|
+
free: 3,
|
|
114
115
|
pro: Infinity,
|
|
115
116
|
business: Infinity,
|
|
116
117
|
team: Infinity,
|
|
@@ -118,57 +119,36 @@ const TIER_LIMITS = {
|
|
|
118
119
|
|
|
119
120
|
function getUpgradeMessage() {
|
|
120
121
|
const tier = getLicenseTier();
|
|
121
|
-
if (tier === 'free') return `Unlimited analyses with Pro — $
|
|
122
|
+
if (tier === 'free') return `Unlimited analyses with Pro — $19/mo → ${UPGRADE_LINKS.free}`;
|
|
122
123
|
if (tier === 'pro') return `Upgrade to Business — priority support, $29/mo → ${UPGRADE_LINKS.pro}`;
|
|
123
124
|
if (tier === 'business') return `Upgrade to Team — team seats, $79/mo → ${UPGRADE_LINKS.business}`;
|
|
124
125
|
return '';
|
|
125
126
|
}
|
|
126
127
|
|
|
127
128
|
// Show usage-aware upgrade CTA after each free run.
|
|
128
|
-
// count =
|
|
129
|
+
// count = daily usage AFTER this run.
|
|
129
130
|
function showFreeTierCTA(count) {
|
|
130
|
-
const limit = TIER_LIMITS.free; //
|
|
131
|
+
const limit = TIER_LIMITS.free; // 3
|
|
131
132
|
const remaining = Math.max(0, limit - count);
|
|
132
133
|
|
|
133
134
|
// Track that an upgrade prompt was shown after a run (post-run CTA, not a hard block)
|
|
134
|
-
const ctaStrength = remaining === 0 ? 'strong' : remaining <=
|
|
135
|
+
const ctaStrength = remaining === 0 ? 'strong' : remaining <= 1 ? 'warning' : 'nudge';
|
|
135
136
|
recordEvent({ event: 'upgrade_prompt_shown', run_count: count, cta_strength: ctaStrength, cta_context: 'post_run' });
|
|
136
137
|
|
|
137
138
|
blank();
|
|
138
139
|
hr();
|
|
139
140
|
|
|
140
141
|
if (remaining === 0) {
|
|
141
|
-
//
|
|
142
|
-
console.log(` ${
|
|
142
|
+
// Last run of the day — power user nudge
|
|
143
|
+
console.log(` ${YL}${B}${count}/${limit} — that's all your free runs for today.${R}`);
|
|
143
144
|
blank();
|
|
144
|
-
console.log(` ${WH}
|
|
145
|
-
console.log(` ${
|
|
146
|
-
console.log(` ${WH} · Priority support — get answers within 24h${R}`);
|
|
147
|
-
console.log(` ${WH} · Team sharing — share analyses across your team${R}`);
|
|
145
|
+
console.log(` ${WH} Pro: unlimited analyses · JSON/HTML export · bulk mode · $19/mo, cancel anytime${R}`);
|
|
146
|
+
console.log(` ${MG}${B}→ ${UPGRADE_LINKS.free}${R}`);
|
|
148
147
|
blank();
|
|
149
|
-
console.log(` ${
|
|
150
|
-
blank();
|
|
151
|
-
console.log(` ${D}After checkout — 2 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. Run: ${CY}content-grade activate <your-key>${R}`);
|
|
154
|
-
console.log(` ${D} Already have a key? Run step 2 now.${R}`);
|
|
155
|
-
} else if (remaining <= 2) {
|
|
156
|
-
// 1-2 runs left — loss aversion + concrete Pro value
|
|
157
|
-
console.log(` ${YL}${B}${remaining} free analysis${remaining === 1 ? '' : 'es'} remaining (${count}/${limit} used)${R}`);
|
|
158
|
-
blank();
|
|
159
|
-
console.log(` ${WH}${B}Pro: unlimited runs · priority support · team sharing${R}`);
|
|
160
|
-
console.log(` ${WH} · No cap, no resets — grade every piece you publish${R}`);
|
|
161
|
-
console.log(` ${MG}${B}→ Get Pro before you run out ($9/mo): ${CY}${UPGRADE_LINKS.free}${R}`);
|
|
148
|
+
console.log(` ${D}Or come back tomorrow for ${limit} more free runs.${R}`);
|
|
162
149
|
} else {
|
|
163
|
-
// Runs
|
|
164
|
-
|
|
165
|
-
`Pro: unlimited runs · no cap, no resets`,
|
|
166
|
-
`Pro: priority support · 24h response time`,
|
|
167
|
-
`Pro: team sharing · analyze together, no limits`,
|
|
168
|
-
];
|
|
169
|
-
console.log(` ${WH}${remaining} free analysis${remaining === 1 ? '' : 'es'} remaining (${count}/${limit} used)${R}`);
|
|
170
|
-
console.log(` ${WH} ${nudgeBenefits[count % 3]}${R}`);
|
|
171
|
-
console.log(` ${MG}→ Get Pro ($9/mo): ${CY}${UPGRADE_LINKS.free}${R}`);
|
|
150
|
+
// Runs remaining — compact single-line footer
|
|
151
|
+
console.log(` ${D}[ ${count}/${limit} free runs today · ${remaining} remaining · Pro: unlimited ($19/mo) → ${UPGRADE_LINKS.free} ]${R}`);
|
|
172
152
|
}
|
|
173
153
|
hr();
|
|
174
154
|
maybeShowFeedbackCTA(count);
|
|
@@ -239,64 +219,53 @@ function showCommunityNudge() {
|
|
|
239
219
|
}
|
|
240
220
|
|
|
241
221
|
// Single-line usage counter appended after every command run.
|
|
242
|
-
// count =
|
|
222
|
+
// count = daily runs used (after this run).
|
|
243
223
|
function showUsageFooter(count) {
|
|
244
224
|
if (isProUser()) return;
|
|
245
225
|
const limit = TIER_LIMITS.free;
|
|
246
226
|
const remaining = Math.max(0, limit - count);
|
|
247
227
|
blank();
|
|
248
228
|
if (remaining === 0) {
|
|
249
|
-
console.log(` ${RD}[
|
|
250
|
-
} else if (remaining <=
|
|
251
|
-
console.log(` ${YL}[ ${remaining} free analysis
|
|
229
|
+
console.log(` ${RD}[ ${limit}/${limit} free analyses used today · Pro: unlimited analyses, JSON/HTML export, bulk mode — $19/mo → ${UPGRADE_LINKS.free} ]${R}`);
|
|
230
|
+
} else if (remaining <= 1) {
|
|
231
|
+
console.log(` ${YL}[ ${remaining} free analysis remaining today · Pro: unlimited analyses, JSON/HTML export, bulk mode — $19/mo → ${UPGRADE_LINKS.free} ]${R}`);
|
|
252
232
|
} else {
|
|
253
|
-
console.log(` ${D}[ ${count}/${limit} free analyses
|
|
233
|
+
console.log(` ${D}[ ${count}/${limit} free analyses today · ${remaining} remaining · Pro: unlimited ($19/mo) → ${UPGRADE_LINKS.free} ]${R}`);
|
|
254
234
|
}
|
|
255
235
|
maybeShowEarlyAdopterCTA(count);
|
|
256
236
|
maybeShowFeedbackCTA(count);
|
|
257
237
|
}
|
|
258
238
|
|
|
259
|
-
// Returns { ok: boolean, count: number, limit: number } for tier-aware
|
|
260
|
-
// Used by batch mode to stop processing when the
|
|
239
|
+
// Returns { ok: boolean, count: number, limit: number } for tier-aware daily limit checks.
|
|
240
|
+
// Used by batch mode to stop processing when the daily limit is reached.
|
|
261
241
|
// Pro tier has Infinity limit and always returns ok: true.
|
|
262
|
-
function
|
|
242
|
+
function checkDailyLimit() {
|
|
263
243
|
const tier = getLicenseTier();
|
|
264
244
|
const limit = TIER_LIMITS[tier] ?? TIER_LIMITS.free;
|
|
265
245
|
if (limit === Infinity) return { ok: true, count: 0, limit: Infinity };
|
|
266
246
|
const usage = getUsage();
|
|
267
|
-
const count = usage.
|
|
247
|
+
const count = usage.daily || 0;
|
|
268
248
|
return { ok: count < limit, count, limit };
|
|
269
249
|
}
|
|
270
250
|
|
|
271
|
-
// Block a run before it starts if the free
|
|
251
|
+
// Block a run before it starts if the free daily limit is exhausted.
|
|
272
252
|
// Returns true (blocked) and prints a visually distinct upgrade prompt.
|
|
273
253
|
// Returns false if the user may proceed.
|
|
274
254
|
function checkFreeTierLimit() {
|
|
275
255
|
if (isProUser()) return false;
|
|
276
256
|
const usage = getUsage();
|
|
277
257
|
const limit = TIER_LIMITS.free;
|
|
278
|
-
if (usage.
|
|
258
|
+
if (usage.daily < limit) return false;
|
|
279
259
|
|
|
280
260
|
// Track funnel event — user hit the limit and saw the upgrade prompt
|
|
281
261
|
recordEvent({ event: 'free_limit_hit', version: _version });
|
|
282
|
-
recordEvent({ event: 'upgrade_prompt_shown', run_count: usage.
|
|
262
|
+
recordEvent({ event: 'upgrade_prompt_shown', run_count: usage.daily });
|
|
283
263
|
|
|
284
264
|
blank();
|
|
285
|
-
|
|
286
|
-
console.log(` ${
|
|
287
|
-
|
|
288
|
-
console.log(` ${
|
|
289
|
-
console.log(` ${WH} · Unlimited runs — no cap, no monthly resets${R}`);
|
|
290
|
-
console.log(` ${WH} · Priority support — get answers within 24h${R}`);
|
|
291
|
-
console.log(` ${WH} · Team sharing — share analyses across your team${R}`);
|
|
292
|
-
blank();
|
|
293
|
-
console.log(` ${MG}${B}→ Get Pro ($9/mo, cancel anytime): ${CY}${UPGRADE_LINKS.free}${R}`);
|
|
294
|
-
blank();
|
|
295
|
-
console.log(` ${D}After checkout — 2 steps to unlock:${R}`);
|
|
296
|
-
console.log(` ${D} 1. Get your key: ${CY}https://content-grade.onrender.com/my-license${R}`);
|
|
297
|
-
console.log(` ${D} 2. Run: ${CY}content-grade activate <your-key>${R}`);
|
|
298
|
-
console.log(` ${D} Already have a key? Run step 2 now.${R}`);
|
|
299
|
-
hr();
|
|
265
|
+
console.log(` ${RD}${B}${limit}/${limit} free analyses used today.${R}`);
|
|
266
|
+
console.log(` ${WH}Pro: unlimited analyses · JSON/HTML export · bulk mode — $19/mo, cancel anytime${R}`);
|
|
267
|
+
console.log(` ${MG}${B}→ ${UPGRADE_LINKS.free}${R}`);
|
|
268
|
+
console.log(` ${D}After purchase: content-grade activate <key>${R}`);
|
|
300
269
|
blank();
|
|
301
270
|
return true;
|
|
302
271
|
}
|
|
@@ -976,7 +945,7 @@ async function cmdInit() {
|
|
|
976
945
|
console.log(` ${CY}content-grade start${R}`);
|
|
977
946
|
blank();
|
|
978
947
|
}
|
|
979
|
-
console.log(` ${WH}Pro: unlimited analyses
|
|
948
|
+
console.log(` ${WH}Pro: unlimited analyses · JSON/HTML export · bulk mode · CI integration — $19/mo, cancel anytime${R}`);
|
|
980
949
|
console.log(` ${MG}→ Get Pro: ${CY}${UPGRADE_LINKS.free}${R}`);
|
|
981
950
|
console.log(` ${D}After checkout: content-grade activate <your-key>${R}`);
|
|
982
951
|
blank();
|
|
@@ -1008,7 +977,7 @@ async function cmdActivate() {
|
|
|
1008
977
|
return;
|
|
1009
978
|
}
|
|
1010
979
|
|
|
1011
|
-
console.log(` ${D}Pro unlocks unlimited analyses
|
|
980
|
+
console.log(` ${D}Pro unlocks unlimited analyses, JSON/HTML export, and bulk mode for $19/mo:${R}`);
|
|
1012
981
|
blank();
|
|
1013
982
|
console.log(` ${MG}${B}→ Get Pro: ${CY}${UPGRADE_LINKS.free}${R}`);
|
|
1014
983
|
blank();
|
|
@@ -1146,9 +1115,9 @@ async function cmdBatch(dirPath) {
|
|
|
1146
1115
|
blank();
|
|
1147
1116
|
console.log(` ${D}Grade every file in a directory in one shot. Pro only.${R}`);
|
|
1148
1117
|
blank();
|
|
1149
|
-
console.log(` ${WH}${B}Pro ($
|
|
1118
|
+
console.log(` ${WH}${B}Pro ($19/mo): unlimited analyses · JSON/HTML export · bulk mode · CI integration${R}`);
|
|
1150
1119
|
blank();
|
|
1151
|
-
console.log(` ${MG}${B}→ Get Pro ($
|
|
1120
|
+
console.log(` ${MG}${B}→ Get Pro ($19/mo, cancel anytime): ${CY}${UPGRADE_LINKS.free}${R}`);
|
|
1152
1121
|
blank();
|
|
1153
1122
|
console.log(` ${D}After checkout — 2 steps to unlock:${R}`);
|
|
1154
1123
|
console.log(` ${D} 1. Get your key: ${CY}https://content-grade.onrender.com/my-license${R}`);
|
|
@@ -1229,12 +1198,12 @@ async function cmdBatch(dirPath) {
|
|
|
1229
1198
|
const rel = f.startsWith(process.cwd()) ? f.slice(process.cwd().length + 1) : f;
|
|
1230
1199
|
process.stdout.write(` ${D}[${i + 1}/${files.length}]${R} ${rel}...`);
|
|
1231
1200
|
|
|
1232
|
-
// Guard: check
|
|
1233
|
-
const batchLimitCheck =
|
|
1201
|
+
// Guard: check daily limit before each analysis
|
|
1202
|
+
const batchLimitCheck = checkDailyLimit();
|
|
1234
1203
|
if (!batchLimitCheck.ok) {
|
|
1235
1204
|
process.stdout.write(` ${YL}limit reached${R}\n`);
|
|
1236
1205
|
blank();
|
|
1237
|
-
warn(`Free limit reached (${batchLimitCheck.count}/${batchLimitCheck.limit}
|
|
1206
|
+
warn(`Free limit reached (${batchLimitCheck.count}/${batchLimitCheck.limit} analyses used today). Remaining files skipped.`);
|
|
1238
1207
|
break;
|
|
1239
1208
|
}
|
|
1240
1209
|
|
|
@@ -1283,7 +1252,7 @@ async function cmdBatch(dirPath) {
|
|
|
1283
1252
|
|
|
1284
1253
|
if (_jsonMode) process.stdout.write(JSON.stringify(results, null, 2) + '\n');
|
|
1285
1254
|
|
|
1286
|
-
if (!isProUser() && results.length) showUsageFooter(getUsage().
|
|
1255
|
+
if (!isProUser() && results.length) showUsageFooter(getUsage().daily);
|
|
1287
1256
|
if (results.length) showCommunityNudge();
|
|
1288
1257
|
}
|
|
1289
1258
|
|
|
@@ -1361,7 +1330,7 @@ function cmdStart() {
|
|
|
1361
1330
|
info(` EmailForge — ${url}/email-forge`);
|
|
1362
1331
|
info(` AudienceDecoder — ${url}/audience`);
|
|
1363
1332
|
blank();
|
|
1364
|
-
info(`Free tier: 15 analyses total. Unlimited with Pro ($
|
|
1333
|
+
info(`Free tier: 15 analyses total. Unlimited with Pro ($19/mo) → ${UPGRADE_LINKS.free}`);
|
|
1365
1334
|
info(`Press Ctrl+C to stop`);
|
|
1366
1335
|
blank();
|
|
1367
1336
|
openBrowser(url);
|
|
@@ -1636,7 +1605,7 @@ function cmdHelp() {
|
|
|
1636
1605
|
console.log(` ${B}PRICING${R}`);
|
|
1637
1606
|
blank();
|
|
1638
1607
|
console.log(` Free 15 analyses total $0`);
|
|
1639
|
-
console.log(` Pro Unlimited analyses $
|
|
1608
|
+
console.log(` Pro Unlimited analyses $19/mo (cancel anytime)`);
|
|
1640
1609
|
console.log(` Business Unlimited analyses $29/mo`);
|
|
1641
1610
|
console.log(` Team Unlimited analyses $79/mo`);
|
|
1642
1611
|
blank();
|
package/dist/landing.html
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"@type": "Offer",
|
|
37
37
|
"price": "0",
|
|
38
38
|
"priceCurrency": "USD",
|
|
39
|
-
"description": "Free:
|
|
39
|
+
"description": "Free: 15 analyses total. Pro: $9/mo, unlimited. Business: $29/mo, unlimited. Team: $79/mo, unlimited + shared workspace."
|
|
40
40
|
},
|
|
41
41
|
"featureList": [
|
|
42
42
|
"Headline analyzer with framework-based scoring",
|
|
@@ -631,13 +631,14 @@
|
|
|
631
631
|
|
|
632
632
|
.pricing-grid {
|
|
633
633
|
display: grid;
|
|
634
|
-
grid-template-columns: repeat(
|
|
635
|
-
gap:
|
|
636
|
-
max-width:
|
|
634
|
+
grid-template-columns: repeat(4, 1fr);
|
|
635
|
+
gap: 20px;
|
|
636
|
+
max-width: 1160px;
|
|
637
637
|
margin: 0 auto;
|
|
638
638
|
}
|
|
639
639
|
|
|
640
|
-
@media (max-width:
|
|
640
|
+
@media (max-width: 1100px) { .pricing-grid { grid-template-columns: repeat(2, 1fr); max-width: 720px; } }
|
|
641
|
+
@media (max-width: 600px) { .pricing-grid { grid-template-columns: 1fr; max-width: 480px; } }
|
|
641
642
|
|
|
642
643
|
/* === SOCIAL PROOF === */
|
|
643
644
|
.social-proof {
|
|
@@ -1016,7 +1017,7 @@
|
|
|
1016
1017
|
</div>
|
|
1017
1018
|
|
|
1018
1019
|
<div class="hero-meta">
|
|
1019
|
-
<span>Free ·
|
|
1020
|
+
<span>Free · 15 analyses to start</span>
|
|
1020
1021
|
<span class="hero-meta-sep">·</span>
|
|
1021
1022
|
<span>Claude CLI required · Zero data leaves your machine</span>
|
|
1022
1023
|
<span class="hero-meta-sep">·</span>
|
|
@@ -1195,7 +1196,7 @@
|
|
|
1195
1196
|
<div class="step">
|
|
1196
1197
|
<div class="step-num">3</div>
|
|
1197
1198
|
<h3>Launch the full dashboard</h3>
|
|
1198
|
-
<p>Start the web interface to access all 6 tools — HeadlineGrader, PageRoast, AdScorer, ThreadGrader, EmailForge, and AudienceDecoder. Free tier:
|
|
1199
|
+
<p>Start the web interface to access all 6 tools — HeadlineGrader, PageRoast, AdScorer, ThreadGrader, EmailForge, and AudienceDecoder. Free tier: 15 analyses total across all tools.</p>
|
|
1199
1200
|
<div class="step-code">npx content-grade start</div>
|
|
1200
1201
|
</div>
|
|
1201
1202
|
</div>
|
|
@@ -1207,8 +1208,9 @@
|
|
|
1207
1208
|
<div class="container">
|
|
1208
1209
|
<div class="pricing-header">
|
|
1209
1210
|
<div class="section-eyebrow">Pricing</div>
|
|
1210
|
-
<h2>
|
|
1211
|
-
<p class="pricing-
|
|
1211
|
+
<h2>Stop guessing if your content is good.</h2>
|
|
1212
|
+
<p class="pricing-subhead" style="font-size:20px; font-weight:600; color:var(--fg); margin-bottom:8px;">Pick a plan. Grade everything.</p>
|
|
1213
|
+
<p class="pricing-lead">3 analyses per day — free. No credit card, no signup, no API key required.</p>
|
|
1212
1214
|
</div>
|
|
1213
1215
|
|
|
1214
1216
|
<div class="pricing-grid">
|
|
@@ -1218,57 +1220,59 @@
|
|
|
1218
1220
|
<div class="plan-period">forever · no signup required</div>
|
|
1219
1221
|
<a href="https://www.npmjs.com/package/content-grade" class="plan-cta">Install free →</a>
|
|
1220
1222
|
<ul class="plan-features">
|
|
1221
|
-
<li><span class="check">✓</span> <strong>3 analyses
|
|
1222
|
-
<li><span class="check">✓</span>
|
|
1223
|
-
<li><span class="check">✓</span>
|
|
1224
|
-
<li><span class="check">✓</span> AI rewrites with technique labels</li>
|
|
1225
|
-
<li><span class="check">✓</span> Per-dimension score breakdown</li>
|
|
1226
|
-
<li><span class="check">✓</span> HeadlineGrader SERP preview</li>
|
|
1223
|
+
<li><span class="check">✓</span> <strong>3 analyses per day</strong> — enough to build the habit</li>
|
|
1224
|
+
<li><span class="check">✓</span> Access all 6 tools: HeadlineGrader, PageRoast, AdScorer, ThreadGrader, EmailForge, AudienceDecoder</li>
|
|
1225
|
+
<li><span class="check">✓</span> Core scores: Readability, Clarity, SEO Signal, Engagement potential</li>
|
|
1227
1226
|
</ul>
|
|
1228
1227
|
</div>
|
|
1229
1228
|
|
|
1230
1229
|
<div class="plan featured">
|
|
1231
1230
|
<div class="plan-badge">Most popular</div>
|
|
1232
1231
|
<div class="plan-name">PRO</div>
|
|
1233
|
-
<div class="plan-price">$
|
|
1234
|
-
<div class="plan-period">Unlimited analyses
|
|
1235
|
-
<a href="https://buy.stripe.com/4gM14p87GeCh9vn9ks8k80a" class="plan-cta" target="_blank" rel="noopener">
|
|
1232
|
+
<div class="plan-price">$19<span>/mo</span></div>
|
|
1233
|
+
<div class="plan-period">Unlimited analyses · billed monthly</div>
|
|
1234
|
+
<a href="https://buy.stripe.com/4gM14p87GeCh9vn9ks8k80a" class="plan-cta" target="_blank" rel="noopener">Upgrade to Pro →</a>
|
|
1235
|
+
<div style="font-size:13px; color:var(--muted); margin-bottom:12px;">Used by content teams grading 50+ pieces per week.</div>
|
|
1236
1236
|
<ul class="plan-features">
|
|
1237
|
-
<li><span class="check">✓</span> <strong>Unlimited analyses
|
|
1238
|
-
<li><span class="check">✓</span>
|
|
1239
|
-
<li><span class="check">✓</span>
|
|
1240
|
-
<li><span class="check">✓</span> Batch mode — analyze whole directories</li>
|
|
1241
|
-
<li><span class="check">✓</span> Priority email support</li>
|
|
1242
|
-
<li><span class="check">✓</span> $0.45/analysis — less than a coffee per day</li>
|
|
1237
|
+
<li><span class="check">✓</span> <strong>Unlimited analyses</strong> — no daily cap, no throttle</li>
|
|
1238
|
+
<li><span class="check">✓</span> Export results as JSON or HTML — pipe into dashboards, Notion, or CI</li>
|
|
1239
|
+
<li><span class="check">✓</span> <code>--bulk</code> mode: grade entire folders, get a ranked quality report</li>
|
|
1243
1240
|
</ul>
|
|
1244
1241
|
</div>
|
|
1245
1242
|
|
|
1246
1243
|
<div class="plan">
|
|
1247
1244
|
<div class="plan-name">BUSINESS</div>
|
|
1248
|
-
<div class="plan-price">$
|
|
1249
|
-
<div class="plan-period">
|
|
1245
|
+
<div class="plan-price">$49<span>/mo</span></div>
|
|
1246
|
+
<div class="plan-period">Unlimited analyses · billed monthly</div>
|
|
1250
1247
|
<a href="https://buy.stripe.com/bJefZjafO2Tz36Z2W48k80b" class="plan-cta" target="_blank" rel="noopener">Get Business →</a>
|
|
1251
1248
|
<ul class="plan-features">
|
|
1252
|
-
<li><span class="check">✓</span> <strong>100 analyses/day</strong></li>
|
|
1253
1249
|
<li><span class="check">✓</span> Everything in Pro</li>
|
|
1254
|
-
<li><span class="check">✓</span>
|
|
1255
|
-
<li><span class="check">✓</span>
|
|
1250
|
+
<li><span class="check">✓</span> CI mode with exit codes — fail builds when content quality drops</li>
|
|
1251
|
+
<li><span class="check">✓</span> <code>--compare</code> flag: score a rewrite against the original</li>
|
|
1252
|
+
<li><span class="check">✓</span> REST API access for custom CMS or analytics integrations</li>
|
|
1256
1253
|
</ul>
|
|
1257
1254
|
</div>
|
|
1258
1255
|
|
|
1259
1256
|
<div class="plan">
|
|
1260
1257
|
<div class="plan-name">TEAM</div>
|
|
1261
|
-
<div class="plan-price">$
|
|
1262
|
-
<div class="plan-period">
|
|
1258
|
+
<div class="plan-price">$199<span>/mo</span></div>
|
|
1259
|
+
<div class="plan-period">Unlimited analyses · billed monthly</div>
|
|
1263
1260
|
<a href="https://buy.stripe.com/cNiaEZfA8cu9bDv4088k80c" class="plan-cta" target="_blank" rel="noopener">Get Team →</a>
|
|
1264
1261
|
<ul class="plan-features">
|
|
1265
|
-
<li><span class="check">✓</span>
|
|
1266
|
-
<li><span class="check">✓</span>
|
|
1267
|
-
<li><span class="check">✓</span>
|
|
1268
|
-
<li><span class="check">✓</span> Dedicated support + SLA</li>
|
|
1262
|
+
<li><span class="check">✓</span> Everything in Business, up to 10 seats under one license key</li>
|
|
1263
|
+
<li><span class="check">✓</span> Priority support with 24-hour response SLA</li>
|
|
1264
|
+
<li><span class="check">✓</span> Early access to new tools before public release</li>
|
|
1269
1265
|
</ul>
|
|
1270
1266
|
</div>
|
|
1271
1267
|
</div>
|
|
1268
|
+
|
|
1269
|
+
<div style="margin-top:32px; padding:20px 24px; background:rgba(255,255,255,0.04); border:1px solid rgba(255,255,255,0.1); border-radius:10px; max-width:560px; margin-left:auto; margin-right:auto; text-align:left;">
|
|
1270
|
+
<div style="font-size:13px; color:rgba(255,255,255,0.5); text-transform:uppercase; letter-spacing:1px; margin-bottom:10px;">After checkout — 2 steps to unlock Pro</div>
|
|
1271
|
+
<ol style="padding-left:20px; color:rgba(255,255,255,0.8); font-size:15px; line-height:1.9; margin:0;">
|
|
1272
|
+
<li>Get your license key: <a href="https://content-grade.onrender.com/my-license" target="_blank" rel="noopener" style="color:#a78bfa;">content-grade.onrender.com/my-license</a></li>
|
|
1273
|
+
<li>Run: <code style="background:rgba(255,255,255,0.08); padding:2px 8px; border-radius:4px; font-size:13px;">content-grade activate <your-key></code></li>
|
|
1274
|
+
</ol>
|
|
1275
|
+
</div>
|
|
1272
1276
|
</div>
|
|
1273
1277
|
</section>
|
|
1274
1278
|
|
|
@@ -1293,7 +1297,7 @@
|
|
|
1293
1297
|
<details>
|
|
1294
1298
|
<summary>Do I need an Anthropic API key or a paid Claude account?</summary>
|
|
1295
1299
|
<div class="faq-answer">
|
|
1296
|
-
No API key required. ContentGrade runs on <strong>Claude CLI</strong> — install it for free from claude.ai/code and log in with a Claude account. A free Claude account is sufficient for the free tier (
|
|
1300
|
+
No API key required. ContentGrade runs on <strong>Claude CLI</strong> — install it for free from claude.ai/code and log in with a Claude account. A free Claude account is sufficient for the free tier (15 analyses total across all tools).<br /><br />
|
|
1297
1301
|
There's no per-query Anthropic billing. You're not routing calls through the API console or accumulating usage charges. Claude CLI handles authentication locally, which is also why your content never leaves your machine.
|
|
1298
1302
|
</div>
|
|
1299
1303
|
</details>
|
|
@@ -1325,7 +1329,21 @@
|
|
|
1325
1329
|
<summary>Can I use ContentGrade for client work at an agency?</summary>
|
|
1326
1330
|
<div class="faq-answer">
|
|
1327
1331
|
Yes, and this is a primary use case. Because ContentGrade runs locally via Claude CLI, client copy never leaves your machine. There's no SaaS terms of service to worry about, no vendor data retention, and no risk of your client's unreleased campaign copy appearing in someone else's training data.<br /><br />
|
|
1328
|
-
Pro tier includes
|
|
1332
|
+
Pro tier includes unlimited analyses, and Team tier includes shared workspace features — share analyses and scoring history across your team without routing content through any third-party service.
|
|
1333
|
+
</div>
|
|
1334
|
+
</details>
|
|
1335
|
+
|
|
1336
|
+
<details>
|
|
1337
|
+
<summary>Can I cancel anytime?</summary>
|
|
1338
|
+
<div class="faq-answer">
|
|
1339
|
+
Yes. Cancel from your account dashboard — takes 10 seconds. No retention flow, no questions, no email chains. Your subscription stops at the end of the billing period.
|
|
1340
|
+
</div>
|
|
1341
|
+
</details>
|
|
1342
|
+
|
|
1343
|
+
<details>
|
|
1344
|
+
<summary>What counts as an analysis?</summary>
|
|
1345
|
+
<div class="faq-answer">
|
|
1346
|
+
One run of any tool on any single piece of content. Grading a headline = 1 analysis. Roasting a landing page = 1 analysis. Running <code>--bulk</code> on a folder of 20 posts = 20 analyses. The Free tier gives you 3 per day — Pro and above are unlimited.
|
|
1329
1347
|
</div>
|
|
1330
1348
|
</details>
|
|
1331
1349
|
|
|
@@ -1399,7 +1417,7 @@
|
|
|
1399
1417
|
<section class="final-cta">
|
|
1400
1418
|
<div class="container">
|
|
1401
1419
|
<h2>Run your best headline.<br />See where it actually stands.</h2>
|
|
1402
|
-
<p>Free ·
|
|
1420
|
+
<p>Free · 15 analyses to start · No API key · Claude CLI only</p>
|
|
1403
1421
|
<div style="display: flex; gap: 16px; justify-content: center; flex-wrap: wrap;">
|
|
1404
1422
|
<a href="https://github.com/Content-Grade/Content-Grade" class="btn-primary">
|
|
1405
1423
|
Install free — npx content-grade
|
|
@@ -75,6 +75,29 @@ export function registerAnalyticsRoutes(app) {
|
|
|
75
75
|
}
|
|
76
76
|
return { ok: true };
|
|
77
77
|
});
|
|
78
|
+
// ── Preflight Suite telemetry/events — the endpoint all CLI tools point to ─
|
|
79
|
+
// stepproof, agent-comply, agent-gate, agent-trace all POST here.
|
|
80
|
+
// Accepts camelCase fields (installId, nodeVersion) as sent by the CLIs.
|
|
81
|
+
// Always returns 200 — fire-and-forget compatible.
|
|
82
|
+
app.post('/api/telemetry/events', async (req) => {
|
|
83
|
+
try {
|
|
84
|
+
const body = req.body;
|
|
85
|
+
const installId = body?.installId ?? body?.install_id;
|
|
86
|
+
if (!body || typeof installId !== 'string' || !installId) {
|
|
87
|
+
return { ok: true };
|
|
88
|
+
}
|
|
89
|
+
const db = getDb();
|
|
90
|
+
db.prepare(`
|
|
91
|
+
INSERT INTO cli_telemetry
|
|
92
|
+
(install_id, package, event, command, success, version, platform, node_version, exit_code, duration_ms)
|
|
93
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
94
|
+
`).run(String(installId).slice(0, 64), body.package ? String(body.package).slice(0, 64) : null, body.event ? String(body.event).slice(0, 64) : 'run', body.command ? String(body.command).slice(0, 64) : null, typeof body.success === 'boolean' ? (body.success ? 1 : 0) : null, body.version ? String(body.version).slice(0, 32) : null, body.platform ? String(body.platform).slice(0, 32) : null, (body.nodeVersion ?? body.node_version) ? String(body.nodeVersion ?? body.node_version).slice(0, 32) : null, typeof body.exit_code === 'number' ? body.exit_code : null, typeof body.duration_ms === 'number' ? Math.round(body.duration_ms) : null);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// never fail — telemetry is non-critical
|
|
98
|
+
}
|
|
99
|
+
return { ok: true };
|
|
100
|
+
});
|
|
78
101
|
// ── CLI telemetry receiver ────────────────────────────────────────────────
|
|
79
102
|
// Receives events from CLI users who have opted in to telemetry.
|
|
80
103
|
// Always returns 200 — never interrupt a CLI session for analytics.
|
package/package.json
CHANGED