claude-code-templates 1.13.2 → 1.14.1

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.
@@ -0,0 +1,188 @@
1
+ /**
2
+ * TrackingService - Download analytics using GitHub Issues as backend
3
+ * Records component installations for analytics without impacting user experience
4
+ */
5
+
6
+ class TrackingService {
7
+ constructor() {
8
+ this.repoOwner = 'davila7';
9
+ this.repoName = 'claude-code-templates';
10
+ this.trackingEnabled = this.shouldEnableTracking();
11
+ this.timeout = 5000; // 5s timeout for tracking requests
12
+ }
13
+
14
+ /**
15
+ * Check if tracking should be enabled (respects user privacy)
16
+ */
17
+ shouldEnableTracking() {
18
+ // Allow users to opt-out
19
+ if (process.env.CCT_NO_TRACKING === 'true' ||
20
+ process.env.CCT_NO_ANALYTICS === 'true' ||
21
+ process.env.CI === 'true') {
22
+ return false;
23
+ }
24
+
25
+ // Enable by default (anonymous usage data only)
26
+ return true;
27
+ }
28
+
29
+ /**
30
+ * Track a component download/installation
31
+ * @param {string} componentType - 'agent', 'command', or 'mcp'
32
+ * @param {string} componentName - Name of the component
33
+ * @param {object} metadata - Additional context (optional)
34
+ */
35
+ async trackDownload(componentType, componentName, metadata = {}) {
36
+ if (!this.trackingEnabled) {
37
+ return;
38
+ }
39
+
40
+ try {
41
+ // Create tracking payload
42
+ const trackingData = this.createTrackingPayload(componentType, componentName, metadata);
43
+
44
+ // Fire-and-forget tracking (don't block user experience)
45
+ this.sendTrackingData(trackingData)
46
+ .catch(error => {
47
+ // Silent failure - tracking should never impact functionality
48
+ console.debug('📊 Tracking info (non-critical):', error.message);
49
+ });
50
+
51
+ } catch (error) {
52
+ // Silently handle any tracking errors
53
+ console.debug('📊 Analytics error (non-critical):', error.message);
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Create standardized tracking payload
59
+ */
60
+ createTrackingPayload(componentType, componentName, metadata) {
61
+ const timestamp = new Date().toISOString();
62
+
63
+ return {
64
+ event: 'component_download',
65
+ component_type: componentType,
66
+ component_name: componentName,
67
+ timestamp: timestamp,
68
+ session_id: this.generateSessionId(),
69
+ environment: {
70
+ node_version: process.version,
71
+ platform: process.platform,
72
+ arch: process.arch,
73
+ cli_version: this.getCliVersion()
74
+ },
75
+ metadata: metadata
76
+ };
77
+ }
78
+
79
+ /**
80
+ * Send tracking data to GitHub Issues (async, non-blocking)
81
+ */
82
+ async sendTrackingData(trackingData) {
83
+ const title = `📊 ${trackingData.component_type}:${trackingData.component_name} - ${trackingData.timestamp.split('T')[0]}`;
84
+
85
+ const body = `\`\`\`json
86
+ ${JSON.stringify(trackingData, null, 2)}
87
+ \`\`\`
88
+
89
+ <!-- ANALYTICS_DATA -->
90
+ Component: **${trackingData.component_name}** (${trackingData.component_type})
91
+ Platform: ${trackingData.environment.platform} ${trackingData.environment.arch}
92
+ Node: ${trackingData.environment.node_version}
93
+ CLI: ${trackingData.environment.cli_version}
94
+ Session: \`${trackingData.session_id}\`
95
+ `;
96
+
97
+ const controller = new AbortController();
98
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
99
+
100
+ try {
101
+ const response = await fetch(`https://api.github.com/repos/${this.repoOwner}/${this.repoName}/issues`, {
102
+ method: 'POST',
103
+ headers: {
104
+ 'Content-Type': 'application/json',
105
+ 'User-Agent': 'claude-code-templates-cli'
106
+ },
107
+ body: JSON.stringify({
108
+ title: title,
109
+ body: body,
110
+ labels: ['📊 analytics', 'download-tracking', `type:${trackingData.component_type}`]
111
+ }),
112
+ signal: controller.signal
113
+ });
114
+
115
+ clearTimeout(timeoutId);
116
+
117
+ if (!response.ok) {
118
+ throw new Error(`GitHub API responded with ${response.status}`);
119
+ }
120
+
121
+ console.debug('📊 Download tracked successfully');
122
+
123
+ } catch (error) {
124
+ clearTimeout(timeoutId);
125
+ throw error;
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Generate a session ID for grouping related downloads
131
+ */
132
+ generateSessionId() {
133
+ return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
134
+ }
135
+
136
+ /**
137
+ * Get CLI version from package.json
138
+ */
139
+ getCliVersion() {
140
+ try {
141
+ const path = require('path');
142
+ const fs = require('fs');
143
+ const packagePath = path.join(__dirname, '..', 'package.json');
144
+ const packageData = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
145
+ return packageData.version || 'unknown';
146
+ } catch (error) {
147
+ return 'unknown';
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Track template installation (full project setup)
153
+ */
154
+ async trackTemplateInstallation(language, framework, metadata = {}) {
155
+ return this.trackDownload('template', `${language}/${framework}`, {
156
+ ...metadata,
157
+ installation_type: 'full_template'
158
+ });
159
+ }
160
+
161
+ /**
162
+ * Track health check usage
163
+ */
164
+ async trackHealthCheck(results = {}) {
165
+ return this.trackDownload('health-check', 'system-validation', {
166
+ installation_type: 'health_check',
167
+ results_summary: results
168
+ });
169
+ }
170
+
171
+ /**
172
+ * Track analytics dashboard usage
173
+ */
174
+ async trackAnalyticsDashboard(metadata = {}) {
175
+ return this.trackDownload('analytics', 'dashboard-launch', {
176
+ installation_type: 'analytics_dashboard',
177
+ ...metadata
178
+ });
179
+ }
180
+ }
181
+
182
+ // Export singleton instance
183
+ const trackingService = new TrackingService();
184
+
185
+ module.exports = {
186
+ TrackingService,
187
+ trackingService
188
+ };