content-grade 1.0.27 → 1.0.28
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
CHANGED
|
@@ -91,7 +91,7 @@ function incrementUsage() {
|
|
|
91
91
|
|
|
92
92
|
// Upgrade links — Free → Pro → Business → Team
|
|
93
93
|
const UPGRADE_LINKS = {
|
|
94
|
-
free: 'https://
|
|
94
|
+
free: 'https://content-grade.github.io/Content-Grade/#pricing', // Pro $9/mo — pricing page first
|
|
95
95
|
pro: 'https://buy.stripe.com/bJefZjafO2Tz36Z2W48k80b', // Business $29/mo
|
|
96
96
|
business: 'https://buy.stripe.com/cNiaEZfA8cu9bDv4088k80c', // Team $79/mo
|
|
97
97
|
};
|
package/bin/telemetry.js
CHANGED
|
@@ -58,18 +58,32 @@ export function isOptedOut() {
|
|
|
58
58
|
return cfg?.telemetryEnabled === false;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Return run count bucket label from total lifetime runs.
|
|
63
|
+
* Buckets: 1-5, 6-20, 21-50, 50+
|
|
64
|
+
*/
|
|
65
|
+
export function getRunCountBucket(totalRuns) {
|
|
66
|
+
if (totalRuns <= 5) return '1-5';
|
|
67
|
+
if (totalRuns <= 20) return '6-20';
|
|
68
|
+
if (totalRuns <= 50) return '21-50';
|
|
69
|
+
return '50+';
|
|
70
|
+
}
|
|
71
|
+
|
|
61
72
|
/**
|
|
62
73
|
* Initialise telemetry on CLI startup.
|
|
63
|
-
*
|
|
74
|
+
* Increments total run count and returns { installId, totalRuns, runCountBucket, isNew, optedOut }.
|
|
64
75
|
* isNew=true means this is the first time the CLI has run — show the notice.
|
|
65
76
|
*/
|
|
66
77
|
export function initTelemetry() {
|
|
67
|
-
if (isOptedOut()) return { installId: null, isNew: false, optedOut: true };
|
|
78
|
+
if (isOptedOut()) return { installId: null, totalRuns: 0, runCountBucket: '1-5', isNew: false, optedOut: true };
|
|
68
79
|
|
|
69
80
|
const cfg = loadConfig();
|
|
70
81
|
|
|
71
82
|
if (cfg?.installId) {
|
|
72
|
-
|
|
83
|
+
// Increment lifetime run counter
|
|
84
|
+
const totalRuns = (cfg.totalRuns ?? 0) + 1;
|
|
85
|
+
saveConfig({ ...cfg, totalRuns });
|
|
86
|
+
return { installId: cfg.installId, totalRuns, runCountBucket: getRunCountBucket(totalRuns), isNew: false, optedOut: false };
|
|
73
87
|
}
|
|
74
88
|
|
|
75
89
|
// First run — generate anonymous install ID, enabled by default (opt-out available)
|
|
@@ -79,9 +93,10 @@ export function initTelemetry() {
|
|
|
79
93
|
installId,
|
|
80
94
|
installedAt: new Date().toISOString(),
|
|
81
95
|
telemetryEnabled: true,
|
|
96
|
+
totalRuns: 1,
|
|
82
97
|
});
|
|
83
98
|
|
|
84
|
-
return { installId, isNew: true, optedOut: false };
|
|
99
|
+
return { installId, totalRuns: 1, runCountBucket: '1-5', isNew: true, optedOut: false };
|
|
85
100
|
}
|
|
86
101
|
|
|
87
102
|
/**
|
|
@@ -105,10 +120,12 @@ export function recordEvent(data) {
|
|
|
105
120
|
const installId = cfg?.installId;
|
|
106
121
|
if (!installId) return; // shouldn't happen after initTelemetry, but guard
|
|
107
122
|
|
|
123
|
+
const totalRuns = cfg?.totalRuns ?? 1;
|
|
108
124
|
const event = {
|
|
109
125
|
...data,
|
|
110
126
|
package: 'content-grade',
|
|
111
127
|
installId,
|
|
128
|
+
run_count_bucket: data.run_count_bucket ?? getRunCountBucket(totalRuns),
|
|
112
129
|
timestamp: new Date().toISOString(),
|
|
113
130
|
};
|
|
114
131
|
|
package/dist-server/server/db.js
CHANGED
|
@@ -43,9 +43,9 @@ export function registerAnalyticsRoutes(app) {
|
|
|
43
43
|
const db = getDb();
|
|
44
44
|
db.prepare(`
|
|
45
45
|
INSERT INTO cli_telemetry
|
|
46
|
-
(install_id, event, command, is_pro, duration_ms, success, exit_code, score, content_type, version, platform, node_version)
|
|
47
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
48
|
-
`).run(String(body.install_id).slice(0, 64), String(body.event ?? 'unknown').slice(0, 64), body.command ? String(body.command).slice(0, 64) : null, typeof body.is_pro === 'boolean' ? (body.is_pro ? 1 : 0) : null, typeof body.duration_ms === 'number' ? Math.round(body.duration_ms) : null, typeof body.success === 'boolean' ? (body.success ? 1 : 0) : null, typeof body.exit_code === 'number' ? body.exit_code : null, typeof body.score === 'number' ? body.score : null, body.content_type ? String(body.content_type).slice(0, 64) : null, body.version ? String(body.version).slice(0, 32) : null, body.platform ? String(body.platform).slice(0, 32) : null, body.nodeVersion ? String(body.nodeVersion).slice(0, 32) : null);
|
|
46
|
+
(install_id, event, command, is_pro, duration_ms, success, exit_code, score, content_type, version, platform, node_version, run_count_bucket)
|
|
47
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
48
|
+
`).run(String(body.install_id).slice(0, 64), String(body.event ?? 'unknown').slice(0, 64), body.command ? String(body.command).slice(0, 64) : null, typeof body.is_pro === 'boolean' ? (body.is_pro ? 1 : 0) : null, typeof body.duration_ms === 'number' ? Math.round(body.duration_ms) : null, typeof body.success === 'boolean' ? (body.success ? 1 : 0) : null, typeof body.exit_code === 'number' ? body.exit_code : null, typeof body.score === 'number' ? body.score : null, body.content_type ? String(body.content_type).slice(0, 64) : null, body.version ? String(body.version).slice(0, 32) : null, body.platform ? String(body.platform).slice(0, 32) : null, body.nodeVersion ? String(body.nodeVersion).slice(0, 32) : null, body.run_count_bucket ? String(body.run_count_bucket).slice(0, 10) : null);
|
|
49
49
|
}
|
|
50
50
|
catch {
|
|
51
51
|
// never fail — telemetry is non-critical
|
package/package.json
CHANGED