content-grade 1.0.9 → 1.0.11

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/CONTRIBUTING.md CHANGED
@@ -16,7 +16,7 @@ Thanks for wanting to contribute. ContentGrade is a CLI + web dashboard for AI-p
16
16
  ## Local development setup
17
17
 
18
18
  ```bash
19
- git clone https://github.com/StanislavBG/Content-Grade
19
+ git clone https://github.com/Content-Grade/Content-Grade
20
20
  cd Content-Grade
21
21
  pnpm install
22
22
  pnpm dev
@@ -15,7 +15,7 @@
15
15
 
16
16
  import { execFileSync, execFile, spawn } from 'child_process';
17
17
  import { existsSync, readFileSync, mkdirSync, writeFileSync, unlinkSync, statSync } from 'fs';
18
- import { resolve, dirname, basename, extname } from 'path';
18
+ import { resolve, dirname, basename, extname, join } from 'path';
19
19
  import { homedir } from 'os';
20
20
  import { fileURLToPath } from 'url';
21
21
  import { promisify } from 'util';
@@ -113,7 +113,7 @@ function blank() { console.log(''); }
113
113
  function banner() {
114
114
  blank();
115
115
  console.log(`${B}${CY} ╔═══════════════════════════════════════╗${R}`);
116
- console.log(`${B}${CY} ║ ContentGrade · Content Analysis ║${R}`);
116
+ console.log(`${B}${CY} ║ ContentGrade · AI content scoring ║${R}`);
117
117
  console.log(`${B}${CY} ╚═══════════════════════════════════════╝${R}`);
118
118
  blank();
119
119
  }
@@ -1150,16 +1150,104 @@ async function cmdCheckUpdates() {
1150
1150
  blank();
1151
1151
  }
1152
1152
 
1153
+ // ── Metrics ───────────────────────────────────────────────────────────────────
1154
+
1155
+ async function cmdMetrics() {
1156
+ blank();
1157
+ console.log(` ${B}ContentGrade Metrics${R}`);
1158
+ blank();
1159
+
1160
+ // 1. npm download stats (public API, no auth)
1161
+ console.log(` ${B}npm Downloads${R}`);
1162
+ const fetchNpm = (period) => new Promise((resolve) => {
1163
+ const url = `https://api.npmjs.org/downloads/point/${period}/content-grade`;
1164
+ const mod = url.startsWith('https') ? httpsGet : httpGet;
1165
+ const req = mod(url, { timeout: 5000 }, (res) => {
1166
+ let data = '';
1167
+ res.on('data', (c) => data += c);
1168
+ res.on('end', () => {
1169
+ try { resolve(JSON.parse(data)); } catch { resolve(null); }
1170
+ });
1171
+ });
1172
+ req.on('error', () => resolve(null));
1173
+ req.on('timeout', () => { req.destroy(); resolve(null); });
1174
+ });
1175
+
1176
+ const [week, month] = await Promise.all([
1177
+ fetchNpm('last-week'),
1178
+ fetchNpm('last-month'),
1179
+ ]);
1180
+ if (week?.downloads != null) {
1181
+ console.log(` ${D}Last 7 days: ${R}${B}${week.downloads.toLocaleString()}${R} installs`);
1182
+ } else {
1183
+ console.log(` ${D}Last 7 days: ${R}${D}unavailable (offline?)${R}`);
1184
+ }
1185
+ if (month?.downloads != null) {
1186
+ console.log(` ${D}Last 30 days: ${R}${B}${month.downloads.toLocaleString()}${R} installs`);
1187
+ }
1188
+ blank();
1189
+
1190
+ // 2. GitHub repository stats (public API, no auth)
1191
+ console.log(` ${B}GitHub${R}`);
1192
+ const ghData = await new Promise((resolve) => {
1193
+ const req = httpsGet(
1194
+ 'https://api.github.com/repos/StanislavBG/Content-Grade',
1195
+ { headers: { 'User-Agent': `content-grade-cli/${_version}` }, timeout: 5000 },
1196
+ (res) => {
1197
+ let data = '';
1198
+ res.on('data', (c) => data += c);
1199
+ res.on('end', () => { try { resolve(JSON.parse(data)); } catch { resolve(null); } });
1200
+ }
1201
+ );
1202
+ req.on('error', () => resolve(null));
1203
+ req.on('timeout', () => { req.destroy(); resolve(null); });
1204
+ });
1205
+ if (ghData?.stargazers_count != null) {
1206
+ console.log(` ${D}Stars: ${R}${B}${ghData.stargazers_count.toLocaleString()}${R}`);
1207
+ console.log(` ${D}Forks: ${R}${B}${ghData.forks_count.toLocaleString()}${R}`);
1208
+ console.log(` ${D}Open issues: ${R}${B}${ghData.open_issues_count.toLocaleString()}${R}`);
1209
+ console.log(` ${D}Watchers: ${R}${B}${ghData.watchers_count.toLocaleString()}${R}`);
1210
+ } else {
1211
+ console.log(` ${D}Unavailable (offline or rate limited)${R}`);
1212
+ }
1213
+ blank();
1214
+
1215
+ // 3. Local telemetry summary
1216
+ console.log(` ${B}Local Usage${R}`);
1217
+ const eventsFile = join(homedir(), '.content-grade', 'events.jsonl');
1218
+ try {
1219
+ const lines = readFileSync(eventsFile, 'utf8').trim().split('\n').filter(Boolean);
1220
+ const events = lines.map(l => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean);
1221
+ const commands = events.filter(e => e.event === 'command');
1222
+ const installs = events.filter(e => e.event === 'install');
1223
+ const byCmd = {};
1224
+ for (const e of commands) { byCmd[e.command] = (byCmd[e.command] || 0) + 1; }
1225
+ console.log(` ${D}Total runs: ${R}${B}${commands.length}${R}`);
1226
+ console.log(` ${D}Installs: ${R}${B}${installs.length}${R}`);
1227
+ if (Object.keys(byCmd).length) {
1228
+ const top = Object.entries(byCmd).sort((a, b) => b[1] - a[1]).slice(0, 5);
1229
+ console.log(` ${D}Top commands: ${R}${top.map(([k, v]) => `${CY}${k}${R}(${v})`).join(' ')}`);
1230
+ }
1231
+ } catch {
1232
+ console.log(` ${D}No local events yet${R}`);
1233
+ }
1234
+ blank();
1235
+
1236
+ console.log(` ${D}Full install history: ${CY}https://npmjs.com/package/content-grade${R}`);
1237
+ blank();
1238
+ }
1239
+
1153
1240
  // ── Help ──────────────────────────────────────────────────────────────────────
1154
1241
 
1155
1242
  function cmdHelp() {
1156
1243
  banner();
1244
+ console.log(` ${D}AI-powered content quality scoring — readability, SEO, structure analysis${R}`);
1157
1245
  console.log(` ${D}v${_version} · ${CY}content-grade.github.io/Content-Grade${R}`);
1158
1246
  blank();
1159
1247
  console.log(` ${B}QUICK START${R}`);
1160
1248
  blank();
1161
- console.log(` ${CY}npx content-grade headline "Your title here"${R} ${D}# grade a headline (fastest, ~5s)${R}`);
1162
- console.log(` ${CY}npx content-grade analyze ./post.md${R} ${D}# full AI content analysis (~20s)${R}`);
1249
+ console.log(` ${CY}npx content-grade headline "Your Headline Here"${R} ${D}# grade a headline (fastest, ~5s)${R}`);
1250
+ console.log(` ${CY}npx content-grade analyze ./my-post.md${R} ${D}# full AI content analysis (~20s)${R}`);
1163
1251
  console.log(` ${CY}npx content-grade demo${R} ${D}# live demo on sample content${R}`);
1164
1252
  console.log(` ${CY}npx content-grade start${R} ${D}# launch web dashboard (6 tools)${R}`);
1165
1253
  blank();
@@ -1191,6 +1279,8 @@ function cmdHelp() {
1191
1279
  blank();
1192
1280
  console.log(` ${CY}init${R} Run if Claude CLI isn't detected or tools aren't working`);
1193
1281
  blank();
1282
+ console.log(` ${CY}metrics${R} Show npm download counts and local usage stats`);
1283
+ blank();
1194
1284
  console.log(` ${CY}telemetry [on|off]${R} View or toggle anonymous usage tracking`);
1195
1285
  blank();
1196
1286
  console.log(` ${CY}check-updates${R} Check if a newer version is available on npm`);
@@ -1405,7 +1495,8 @@ async function cmdDemo() {
1405
1495
 
1406
1496
  // Show telemetry notice after user has seen value (first run only)
1407
1497
  if (_showTelemNotice) {
1408
- console.log(` ${D}Anonymous usage data is collected by default. Opt out: ${CY}content-grade telemetry off${R}`);
1498
+ console.log(` ${D}Help improve ContentGrade enable anonymous usage analytics: ${CY}content-grade telemetry on${R}`);
1499
+ console.log(` ${D}No PII, no file contents. View what's collected: ${CY}content-grade telemetry${R}`);
1409
1500
  blank();
1410
1501
  }
1411
1502
 
@@ -1745,6 +1836,10 @@ switch (cmd) {
1745
1836
  console.log(`content-grade v${_version}`);
1746
1837
  break;
1747
1838
 
1839
+ case 'metrics':
1840
+ cmdMetrics().catch(() => {});
1841
+ break;
1842
+
1748
1843
  case 'telemetry': {
1749
1844
  const sub = args[1];
1750
1845
  if (sub === 'off') {
package/bin/telemetry.js CHANGED
@@ -72,18 +72,15 @@ export function initTelemetry() {
72
72
  return { installId: cfg.installId, isNew: false, optedOut: false };
73
73
  }
74
74
 
75
- // First run — generate anonymous install ID
75
+ // First run — generate anonymous install ID, opt-IN by default (off until user enables)
76
76
  const installId = generateId();
77
77
  saveConfig({
78
78
  installId,
79
79
  installedAt: new Date().toISOString(),
80
- telemetryEnabled: true,
80
+ telemetryEnabled: false,
81
81
  });
82
82
 
83
- // Record install event
84
- _write({ event: 'install', installId, platform: process.platform, nodeVersion: process.version });
85
-
86
- return { installId, isNew: true, optedOut: false };
83
+ return { installId, isNew: true, optedOut: true };
87
84
  }
88
85
 
89
86
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "content-grade",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
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": {