claude-code-templates 1.19.0 → 1.19.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.
- package/package.json +2 -2
- package/src/index.js +51 -31
- package/src/tracking-service.js +62 -22
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-templates",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.1",
|
|
4
4
|
"description": "CLI tool to setup Claude Code configurations with framework-specific commands, automation hooks and MCP Servers for your projects",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -90,6 +90,6 @@
|
|
|
90
90
|
],
|
|
91
91
|
"devDependencies": {
|
|
92
92
|
"jest": "^30.0.4",
|
|
93
|
-
"jest-watch-typeahead": "^
|
|
93
|
+
"jest-watch-typeahead": "^3.0.1"
|
|
94
94
|
}
|
|
95
95
|
}
|
package/src/index.js
CHANGED
|
@@ -401,8 +401,11 @@ async function installIndividualAgent(agentName, targetDir, options) {
|
|
|
401
401
|
source: 'github_main'
|
|
402
402
|
});
|
|
403
403
|
|
|
404
|
+
return true;
|
|
405
|
+
|
|
404
406
|
} catch (error) {
|
|
405
407
|
console.log(chalk.red(`❌ Error installing agent: ${error.message}`));
|
|
408
|
+
return false;
|
|
406
409
|
}
|
|
407
410
|
}
|
|
408
411
|
|
|
@@ -464,8 +467,11 @@ async function installIndividualCommand(commandName, targetDir, options) {
|
|
|
464
467
|
source: 'github_main'
|
|
465
468
|
});
|
|
466
469
|
|
|
470
|
+
return true;
|
|
471
|
+
|
|
467
472
|
} catch (error) {
|
|
468
473
|
console.log(chalk.red(`❌ Error installing command: ${error.message}`));
|
|
474
|
+
return false;
|
|
469
475
|
}
|
|
470
476
|
}
|
|
471
477
|
|
|
@@ -547,8 +553,11 @@ async function installIndividualMCP(mcpName, targetDir, options) {
|
|
|
547
553
|
source: 'github_main'
|
|
548
554
|
});
|
|
549
555
|
|
|
556
|
+
return true;
|
|
557
|
+
|
|
550
558
|
} catch (error) {
|
|
551
559
|
console.log(chalk.red(`❌ Error installing MCP: ${error.message}`));
|
|
560
|
+
return false;
|
|
552
561
|
}
|
|
553
562
|
}
|
|
554
563
|
|
|
@@ -712,13 +721,20 @@ async function installIndividualSetting(settingName, targetDir, options) {
|
|
|
712
721
|
// Check for conflicting top-level settings
|
|
713
722
|
Object.keys(settingConfig).forEach(key => {
|
|
714
723
|
if (key !== 'permissions' && key !== 'env' && key !== 'hooks' &&
|
|
715
|
-
existingConfig[key] !== undefined && existingConfig[key] !== settingConfig[key]) {
|
|
716
|
-
|
|
724
|
+
existingConfig[key] !== undefined && JSON.stringify(existingConfig[key]) !== JSON.stringify(settingConfig[key])) {
|
|
725
|
+
|
|
726
|
+
// For objects, just indicate the setting name without showing the complex values
|
|
727
|
+
if (typeof existingConfig[key] === 'object' && existingConfig[key] !== null &&
|
|
728
|
+
typeof settingConfig[key] === 'object' && settingConfig[key] !== null) {
|
|
729
|
+
conflicts.push(`Setting "${key}" (will be overwritten with new configuration)`);
|
|
730
|
+
} else {
|
|
731
|
+
conflicts.push(`Setting "${key}" (current: "${existingConfig[key]}", new: "${settingConfig[key]}")`);
|
|
732
|
+
}
|
|
717
733
|
}
|
|
718
734
|
});
|
|
719
735
|
|
|
720
|
-
// Ask user about conflicts if any exist
|
|
721
|
-
if (conflicts.length > 0
|
|
736
|
+
// Ask user about conflicts if any exist
|
|
737
|
+
if (conflicts.length > 0) {
|
|
722
738
|
console.log(chalk.yellow(`\n⚠️ Conflicts detected while installing setting "${settingName}" in ${installLocation}:`));
|
|
723
739
|
conflicts.forEach(conflict => console.log(chalk.gray(` • ${conflict}`)));
|
|
724
740
|
|
|
@@ -734,10 +750,6 @@ async function installIndividualSetting(settingName, targetDir, options) {
|
|
|
734
750
|
console.log(chalk.yellow(`⏹️ Installation of setting "${settingName}" in ${installLocation} cancelled by user.`));
|
|
735
751
|
continue; // Skip this location and continue with others
|
|
736
752
|
}
|
|
737
|
-
} else if (conflicts.length > 0 && options.silent) {
|
|
738
|
-
// In silent mode (batch installation), skip conflicting settings and warn
|
|
739
|
-
console.log(chalk.yellow(`⚠️ Skipping setting "${settingName}" in ${installLocation} due to conflicts (use individual installation to resolve)`));
|
|
740
|
-
continue; // Skip this location and continue with others
|
|
741
753
|
}
|
|
742
754
|
|
|
743
755
|
// Deep merge configurations
|
|
@@ -809,8 +821,11 @@ async function installIndividualSetting(settingName, targetDir, options) {
|
|
|
809
821
|
}
|
|
810
822
|
}
|
|
811
823
|
|
|
824
|
+
return successfulInstallations;
|
|
825
|
+
|
|
812
826
|
} catch (error) {
|
|
813
827
|
console.log(chalk.red(`❌ Error installing setting: ${error.message}`));
|
|
828
|
+
return 0;
|
|
814
829
|
}
|
|
815
830
|
}
|
|
816
831
|
|
|
@@ -966,8 +981,8 @@ async function installIndividualHook(hookName, targetDir, options) {
|
|
|
966
981
|
// This is because Claude Code's array format naturally supports multiple hooks
|
|
967
982
|
// Conflicts are less likely and generally hooks can coexist
|
|
968
983
|
|
|
969
|
-
// Ask user about conflicts if any exist
|
|
970
|
-
if (conflicts.length > 0
|
|
984
|
+
// Ask user about conflicts if any exist
|
|
985
|
+
if (conflicts.length > 0) {
|
|
971
986
|
console.log(chalk.yellow(`\n⚠️ Conflicts detected while installing hook "${hookName}" in ${installLocation}:`));
|
|
972
987
|
conflicts.forEach(conflict => console.log(chalk.gray(` • ${conflict}`)));
|
|
973
988
|
|
|
@@ -983,10 +998,6 @@ async function installIndividualHook(hookName, targetDir, options) {
|
|
|
983
998
|
console.log(chalk.yellow(`⏹️ Installation of hook "${hookName}" in ${installLocation} cancelled by user.`));
|
|
984
999
|
continue; // Skip this location and continue with others
|
|
985
1000
|
}
|
|
986
|
-
} else if (conflicts.length > 0 && options.silent) {
|
|
987
|
-
// In silent mode (batch installation), skip conflicting hooks and warn
|
|
988
|
-
console.log(chalk.yellow(`⚠️ Skipping hook "${hookName}" in ${installLocation} due to conflicts (use individual installation to resolve)`));
|
|
989
|
-
continue; // Skip this location and continue with others
|
|
990
1001
|
}
|
|
991
1002
|
|
|
992
1003
|
// Deep merge configurations with proper hook array structure
|
|
@@ -1066,8 +1077,11 @@ async function installIndividualHook(hookName, targetDir, options) {
|
|
|
1066
1077
|
}
|
|
1067
1078
|
}
|
|
1068
1079
|
|
|
1080
|
+
return successfulInstallations;
|
|
1081
|
+
|
|
1069
1082
|
} catch (error) {
|
|
1070
1083
|
console.log(chalk.red(`❌ Error installing hook: ${error.message}`));
|
|
1084
|
+
return 0;
|
|
1071
1085
|
}
|
|
1072
1086
|
}
|
|
1073
1087
|
|
|
@@ -1208,6 +1222,9 @@ async function installMultipleComponents(options, targetDir) {
|
|
|
1208
1222
|
console.log(chalk.gray(` Settings: ${components.settings.length}`));
|
|
1209
1223
|
console.log(chalk.gray(` Hooks: ${components.hooks.length}`));
|
|
1210
1224
|
|
|
1225
|
+
// Counter for successfully installed components
|
|
1226
|
+
let successfullyInstalled = 0;
|
|
1227
|
+
|
|
1211
1228
|
// Ask for installation locations once for configuration components (if any exist and not in silent mode)
|
|
1212
1229
|
let sharedInstallLocations = ['local']; // default
|
|
1213
1230
|
const hasSettingsOrHooks = components.settings.length > 0 || components.hooks.length > 0;
|
|
@@ -1253,39 +1270,44 @@ async function installMultipleComponents(options, targetDir) {
|
|
|
1253
1270
|
// Install agents
|
|
1254
1271
|
for (const agent of components.agents) {
|
|
1255
1272
|
console.log(chalk.gray(` Installing agent: ${agent}`));
|
|
1256
|
-
await installIndividualAgent(agent, targetDir, { ...options, silent: true });
|
|
1273
|
+
const agentSuccess = await installIndividualAgent(agent, targetDir, { ...options, silent: true });
|
|
1274
|
+
if (agentSuccess) successfullyInstalled++;
|
|
1257
1275
|
}
|
|
1258
1276
|
|
|
1259
1277
|
// Install commands
|
|
1260
1278
|
for (const command of components.commands) {
|
|
1261
1279
|
console.log(chalk.gray(` Installing command: ${command}`));
|
|
1262
|
-
await installIndividualCommand(command, targetDir, { ...options, silent: true });
|
|
1280
|
+
const commandSuccess = await installIndividualCommand(command, targetDir, { ...options, silent: true });
|
|
1281
|
+
if (commandSuccess) successfullyInstalled++;
|
|
1263
1282
|
}
|
|
1264
1283
|
|
|
1265
1284
|
// Install MCPs
|
|
1266
1285
|
for (const mcp of components.mcps) {
|
|
1267
1286
|
console.log(chalk.gray(` Installing MCP: ${mcp}`));
|
|
1268
|
-
await installIndividualMCP(mcp, targetDir, { ...options, silent: true });
|
|
1287
|
+
const mcpSuccess = await installIndividualMCP(mcp, targetDir, { ...options, silent: true });
|
|
1288
|
+
if (mcpSuccess) successfullyInstalled++;
|
|
1269
1289
|
}
|
|
1270
1290
|
|
|
1271
1291
|
// Install settings (using shared installation locations)
|
|
1272
1292
|
for (const setting of components.settings) {
|
|
1273
1293
|
console.log(chalk.gray(` Installing setting: ${setting}`));
|
|
1274
|
-
await installIndividualSetting(setting, targetDir, {
|
|
1294
|
+
const settingSuccess = await installIndividualSetting(setting, targetDir, {
|
|
1275
1295
|
...options,
|
|
1276
1296
|
silent: true,
|
|
1277
1297
|
sharedInstallLocations: sharedInstallLocations
|
|
1278
1298
|
});
|
|
1299
|
+
if (settingSuccess > 0) successfullyInstalled++;
|
|
1279
1300
|
}
|
|
1280
1301
|
|
|
1281
1302
|
// Install hooks (using shared installation locations)
|
|
1282
1303
|
for (const hook of components.hooks) {
|
|
1283
1304
|
console.log(chalk.gray(` Installing hook: ${hook}`));
|
|
1284
|
-
await installIndividualHook(hook, targetDir, {
|
|
1305
|
+
const hookSuccess = await installIndividualHook(hook, targetDir, {
|
|
1285
1306
|
...options,
|
|
1286
1307
|
silent: true,
|
|
1287
1308
|
sharedInstallLocations: sharedInstallLocations
|
|
1288
1309
|
});
|
|
1310
|
+
if (hookSuccess > 0) successfullyInstalled++;
|
|
1289
1311
|
}
|
|
1290
1312
|
|
|
1291
1313
|
// Handle YAML workflow if provided
|
|
@@ -1317,7 +1339,15 @@ async function installMultipleComponents(options, targetDir) {
|
|
|
1317
1339
|
}
|
|
1318
1340
|
}
|
|
1319
1341
|
|
|
1320
|
-
|
|
1342
|
+
if (successfullyInstalled === totalComponents) {
|
|
1343
|
+
console.log(chalk.green(`\n✅ Successfully installed ${successfullyInstalled} components!`));
|
|
1344
|
+
} else if (successfullyInstalled > 0) {
|
|
1345
|
+
console.log(chalk.yellow(`\n⚠️ Successfully installed ${successfullyInstalled} of ${totalComponents} components.`));
|
|
1346
|
+
console.log(chalk.red(`❌ ${totalComponents - successfullyInstalled} component(s) failed to install.`));
|
|
1347
|
+
} else {
|
|
1348
|
+
console.log(chalk.red(`\n❌ No components were installed successfully.`));
|
|
1349
|
+
return; // Exit early if nothing was installed
|
|
1350
|
+
}
|
|
1321
1351
|
console.log(chalk.cyan(`📁 Components installed to: .claude/`));
|
|
1322
1352
|
|
|
1323
1353
|
if (options.yaml) {
|
|
@@ -1325,17 +1355,7 @@ async function installMultipleComponents(options, targetDir) {
|
|
|
1325
1355
|
console.log(chalk.cyan(`🚀 Use the workflow file with Claude Code to execute the complete setup`));
|
|
1326
1356
|
}
|
|
1327
1357
|
|
|
1328
|
-
//
|
|
1329
|
-
trackingService.trackDownload('multi-component', 'batch', {
|
|
1330
|
-
installation_type: 'multi-component',
|
|
1331
|
-
agents_count: components.agents.length,
|
|
1332
|
-
commands_count: components.commands.length,
|
|
1333
|
-
mcps_count: components.mcps.length,
|
|
1334
|
-
settings_count: components.settings.length,
|
|
1335
|
-
hooks_count: components.hooks.length,
|
|
1336
|
-
has_yaml: !!options.yaml,
|
|
1337
|
-
target_directory: path.relative(process.cwd(), targetDir)
|
|
1338
|
-
});
|
|
1358
|
+
// Note: Individual components are already tracked separately in their installation functions
|
|
1339
1359
|
|
|
1340
1360
|
// Handle prompt execution if provided
|
|
1341
1361
|
if (options.prompt) {
|
package/src/tracking-service.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* TrackingService -
|
|
2
|
+
* TrackingService - Anonymous download analytics using Supabase database
|
|
3
3
|
* Records component installations for analytics without impacting user experience
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
class TrackingService {
|
|
7
7
|
constructor() {
|
|
8
|
-
this.repoOwner = 'davila7';
|
|
9
|
-
this.repoName = 'claude-code-templates';
|
|
10
8
|
this.trackingEnabled = this.shouldEnableTracking();
|
|
11
9
|
this.timeout = 5000; // 5s timeout for tracking requests
|
|
12
10
|
}
|
|
@@ -83,35 +81,20 @@ class TrackingService {
|
|
|
83
81
|
}
|
|
84
82
|
|
|
85
83
|
/**
|
|
86
|
-
* Send tracking data
|
|
84
|
+
* Send tracking data to database endpoint
|
|
87
85
|
*/
|
|
88
86
|
async sendTrackingData(trackingData) {
|
|
89
87
|
const controller = new AbortController();
|
|
90
88
|
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
91
89
|
|
|
92
90
|
try {
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
type: trackingData.component_type,
|
|
96
|
-
name: trackingData.component_name,
|
|
97
|
-
platform: trackingData.environment.platform || 'unknown',
|
|
98
|
-
cli: trackingData.environment.cli_version || 'unknown',
|
|
99
|
-
session: trackingData.session_id.substring(0, 8) // Only first 8 chars for privacy
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
// Use GitHub Pages tracking endpoint via custom domain (no auth needed)
|
|
103
|
-
await fetch(`https://aitmpl.com/api/track.html?${params}`, {
|
|
104
|
-
method: 'GET',
|
|
105
|
-
mode: 'no-cors', // Prevents CORS errors
|
|
106
|
-
signal: controller.signal
|
|
107
|
-
});
|
|
91
|
+
// Send to Vercel database endpoint
|
|
92
|
+
await this.sendToDatabase(trackingData, controller.signal);
|
|
108
93
|
|
|
109
94
|
clearTimeout(timeoutId);
|
|
110
95
|
|
|
111
|
-
// No need to check response with no-cors mode
|
|
112
|
-
// Only show success message when debugging
|
|
113
96
|
if (process.env.CCT_DEBUG === 'true') {
|
|
114
|
-
console.debug('📊 Download tracked successfully
|
|
97
|
+
console.debug('📊 Download tracked successfully');
|
|
115
98
|
}
|
|
116
99
|
|
|
117
100
|
} catch (error) {
|
|
@@ -123,6 +106,63 @@ class TrackingService {
|
|
|
123
106
|
}
|
|
124
107
|
}
|
|
125
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Send tracking data to Vercel database
|
|
111
|
+
*/
|
|
112
|
+
async sendToDatabase(trackingData, signal) {
|
|
113
|
+
try {
|
|
114
|
+
// Extract component path from metadata
|
|
115
|
+
const componentPath = trackingData.metadata?.target_directory ||
|
|
116
|
+
trackingData.metadata?.path ||
|
|
117
|
+
trackingData.component_name;
|
|
118
|
+
|
|
119
|
+
// Extract category from metadata or component name
|
|
120
|
+
const category = trackingData.metadata?.category ||
|
|
121
|
+
(trackingData.component_name.includes('/') ?
|
|
122
|
+
trackingData.component_name.split('/')[0] : 'general');
|
|
123
|
+
|
|
124
|
+
const payload = {
|
|
125
|
+
type: trackingData.component_type,
|
|
126
|
+
name: trackingData.component_name,
|
|
127
|
+
path: componentPath,
|
|
128
|
+
category: category,
|
|
129
|
+
cliVersion: trackingData.environment?.cli_version || 'unknown'
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const response = await fetch('https://www.aitmpl.com/api/track-download-supabase', {
|
|
133
|
+
method: 'POST',
|
|
134
|
+
headers: {
|
|
135
|
+
'Content-Type': 'application/json',
|
|
136
|
+
'User-Agent': `claude-code-templates/${trackingData.environment?.cli_version || 'unknown'}`
|
|
137
|
+
},
|
|
138
|
+
body: JSON.stringify(payload),
|
|
139
|
+
signal: signal
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
if (process.env.CCT_DEBUG === 'true') {
|
|
143
|
+
console.debug('📊 Payload sent:', JSON.stringify(payload, null, 2));
|
|
144
|
+
if (response.ok) {
|
|
145
|
+
console.debug('📊 Successfully saved to database');
|
|
146
|
+
} else {
|
|
147
|
+
console.debug(`📊 Database save failed with status: ${response.status}`);
|
|
148
|
+
try {
|
|
149
|
+
const errorText = await response.text();
|
|
150
|
+
console.debug('📊 Error response:', errorText);
|
|
151
|
+
} catch (e) {
|
|
152
|
+
console.debug('📊 Could not read error response');
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
} catch (error) {
|
|
158
|
+
if (process.env.CCT_DEBUG === 'true') {
|
|
159
|
+
console.debug('📊 Database tracking failed:', error.message);
|
|
160
|
+
}
|
|
161
|
+
// Don't throw - tracking should be non-blocking
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
|
|
126
166
|
/**
|
|
127
167
|
* Generate a session ID for grouping related downloads
|
|
128
168
|
*/
|