claude-code-templates 1.4.0 → 1.4.2

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/command-stats.js +101 -19
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-templates",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
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": {
@@ -3,6 +3,31 @@ const path = require('path');
3
3
  const chalk = require('chalk');
4
4
  const { spawn } = require('child_process');
5
5
 
6
+ /**
7
+ * Estimates token count for text content
8
+ * Based on approximate tokenization rules: ~4 characters per token for English text
9
+ * @param {string} text - Text to analyze
10
+ * @returns {number} Estimated token count
11
+ */
12
+ function estimateTokens(text) {
13
+ // Remove excessive whitespace and normalize
14
+ const cleanText = text.replace(/\s+/g, ' ').trim();
15
+
16
+ // Basic estimation: ~4 characters per token for English text
17
+ // Adjust for code content which typically has more tokens per character
18
+ const baseTokens = Math.ceil(cleanText.length / 4);
19
+
20
+ // Adjust for markdown and code content
21
+ const codeBlocks = (text.match(/```[\s\S]*?```/g) || []).length;
22
+ const inlineCode = (text.match(/`[^`]*`/g) || []).length;
23
+ const markdownElements = (text.match(/[#*_\[\]()]/g) || []).length;
24
+
25
+ // Add extra tokens for code and markdown formatting
26
+ const adjustedTokens = baseTokens + (codeBlocks * 5) + (inlineCode * 2) + Math.ceil(markdownElements / 2);
27
+
28
+ return adjustedTokens;
29
+ }
30
+
6
31
  /**
7
32
  * Analyzes existing Claude Code commands in the current project
8
33
  * @param {string} targetDir - Directory to analyze (default: current directory)
@@ -42,6 +67,9 @@ async function analyzeCommands(targetDir = process.cwd()) {
42
67
  const lines = content.split('\n').filter(line => line.trim());
43
68
  const title = lines.find(line => line.startsWith('#')) || file;
44
69
 
70
+ // Calculate token estimate
71
+ const tokenCount = estimateTokens(content);
72
+
45
73
  commands.push({
46
74
  name: file.replace('.md', ''),
47
75
  filename: file,
@@ -49,7 +77,8 @@ async function analyzeCommands(targetDir = process.cwd()) {
49
77
  lastModified: stats.mtime,
50
78
  title: title.replace(/^#+\s*/, ''),
51
79
  lines: lines.length,
52
- wordCount: content.split(/\s+/).length
80
+ wordCount: content.split(/\s+/).length,
81
+ tokens: tokenCount
53
82
  });
54
83
  }
55
84
 
@@ -60,7 +89,8 @@ async function analyzeCommands(targetDir = process.cwd()) {
60
89
  exists: true,
61
90
  commands,
62
91
  total: commands.length,
63
- totalSize: commands.reduce((sum, cmd) => sum + cmd.size, 0)
92
+ totalSize: commands.reduce((sum, cmd) => sum + cmd.size, 0),
93
+ totalTokens: commands.reduce((sum, cmd) => sum + cmd.tokens, 0)
64
94
  };
65
95
  } catch (error) {
66
96
  return {
@@ -76,59 +106,104 @@ async function analyzeCommands(targetDir = process.cwd()) {
76
106
  */
77
107
  function displayCommandStats(analysis) {
78
108
  console.log(chalk.cyan('\nšŸ“Š Claude Code Command Analysis'));
79
- console.log(chalk.gray('═'.repeat(80)));
109
+ console.log(chalk.gray('═'.repeat(97)));
80
110
 
81
111
  if (!analysis.exists) {
82
112
  console.log(chalk.yellow('āš ļø ' + analysis.message));
83
113
  console.log(chalk.blue('\nšŸ’” Run the setup first: npx claude-code-templates'));
84
- return;
114
+ return false; // Indicate no .claude directory
85
115
  }
86
116
 
87
117
  if (analysis.error) {
88
118
  console.log(chalk.red('āŒ ' + analysis.error));
89
- return;
119
+ return false;
90
120
  }
91
121
 
92
122
  if (analysis.commands.length === 0) {
93
123
  console.log(chalk.yellow('āš ļø ' + analysis.message));
94
124
  console.log(chalk.blue('\nšŸ’” No commands found to analyze'));
95
- return;
125
+ return false; // Indicate no commands found
96
126
  }
97
127
 
98
128
  // Summary
99
129
  const totalSizeKB = (analysis.totalSize / 1024).toFixed(1);
100
- console.log(chalk.green(`āœ… Found ${analysis.total} command file(s) (${totalSizeKB} KB total)`));
130
+ const totalTokens = analysis.totalTokens.toLocaleString();
131
+ console.log(chalk.green(`āœ… Found ${analysis.total} command file(s) (${totalSizeKB} KB, ~${totalTokens} tokens total)`));
101
132
  console.log('');
102
133
 
103
134
  // Table header
104
135
  const header = chalk.bold.blue(
105
- 'Command'.padEnd(20) +
106
- 'Size'.padEnd(8) +
107
- 'Lines'.padEnd(8) +
108
- 'Words'.padEnd(8) +
136
+ 'Command'.padEnd(18) +
137
+ 'Size'.padEnd(7) +
138
+ 'Lines'.padEnd(6) +
139
+ 'Words'.padEnd(6) +
140
+ 'Tokens (aprox)'.padEnd(14) +
109
141
  'Last Modified'
110
142
  );
111
143
  console.log(header);
112
- console.log(chalk.gray('─'.repeat(80)));
144
+ console.log(chalk.gray('─'.repeat(97)));
113
145
 
114
146
  // Table rows
115
147
  analysis.commands.forEach(cmd => {
116
- const sizeFormatted = `${(cmd.size / 1024).toFixed(1)}KB`.padEnd(8);
117
- const linesFormatted = cmd.lines.toString().padEnd(8);
118
- const wordsFormatted = cmd.wordCount.toString().padEnd(8);
148
+ const sizeFormatted = `${(cmd.size / 1024).toFixed(1)}KB`.padEnd(7);
149
+ const linesFormatted = cmd.lines.toString().padEnd(6);
150
+ const wordsFormatted = cmd.wordCount.toString().padEnd(6);
151
+ const tokensFormatted = cmd.tokens.toString().padEnd(14);
119
152
  const dateFormatted = cmd.lastModified.toLocaleDateString();
120
153
 
121
- const row = chalk.white(cmd.name.padEnd(20)) +
154
+ const row = chalk.white(cmd.name.padEnd(18)) +
122
155
  chalk.cyan(sizeFormatted) +
123
156
  chalk.yellow(linesFormatted) +
124
157
  chalk.green(wordsFormatted) +
158
+ chalk.magenta(tokensFormatted) +
125
159
  chalk.gray(dateFormatted);
126
160
 
127
161
  console.log(row);
128
162
  });
129
163
 
130
- console.log(chalk.gray('─'.repeat(80)));
131
- console.log(chalk.bold(`Total: ${analysis.total} commands, ${totalSizeKB} KB`));
164
+ console.log(chalk.gray('─'.repeat(97)));
165
+ console.log(chalk.bold(`Total: ${analysis.total} commands, ${totalSizeKB} KB, ~${totalTokens} tokens`));
166
+ return true; // Indicate commands were found and displayed
167
+ }
168
+
169
+ /**
170
+ * Prompts user to setup Claude Code Templates when no commands are found
171
+ * @param {string} targetDir - Project directory
172
+ */
173
+ async function promptSetupWhenNoCommands(targetDir) {
174
+ const inquirer = require('inquirer');
175
+
176
+ console.log(chalk.cyan('\nšŸš€ Claude Code Templates Setup'));
177
+ console.log(chalk.gray('No Claude Code commands found in this project. You can set up Claude Code Templates to get started.'));
178
+
179
+ try {
180
+ const { setupNow } = await inquirer.prompt([{
181
+ type: 'confirm',
182
+ name: 'setupNow',
183
+ message: 'Would you like to start the Claude Code Templates setup now?',
184
+ default: true,
185
+ prefix: chalk.blue('šŸ¤–')
186
+ }]);
187
+
188
+ if (!setupNow) {
189
+ console.log(chalk.yellow('ā­ļø Setup skipped. Run "npx claude-code-templates" anytime to set up your project.'));
190
+ return false;
191
+ }
192
+
193
+ console.log(chalk.blue('\nšŸš€ Starting Claude Code Templates setup...'));
194
+ console.log(chalk.gray('This will guide you through language and framework selection.\n'));
195
+
196
+ // Import and run the main setup function
197
+ const createClaudeConfig = require('./index');
198
+ await createClaudeConfig({ directory: targetDir });
199
+
200
+ return true;
201
+
202
+ } catch (error) {
203
+ console.error(chalk.red('Error during setup:'), error.message);
204
+ console.log(chalk.blue('šŸ’” You can run setup manually with: npx claude-code-templates'));
205
+ return false;
206
+ }
132
207
  }
133
208
 
134
209
  /**
@@ -235,7 +310,13 @@ async function runCommandStats(options = {}) {
235
310
  const analysis = await analyzeCommands(targetDir);
236
311
 
237
312
  // Display results
238
- displayCommandStats(analysis);
313
+ const hasCommands = displayCommandStats(analysis);
314
+
315
+ // If no commands found, offer to start setup
316
+ if (!hasCommands) {
317
+ await promptSetupWhenNoCommands(targetDir);
318
+ return;
319
+ }
239
320
 
240
321
  // Prompt for optimization
241
322
  await promptCommandOptimization(analysis, targetDir);
@@ -245,5 +326,6 @@ module.exports = {
245
326
  analyzeCommands,
246
327
  displayCommandStats,
247
328
  promptCommandOptimization,
329
+ promptSetupWhenNoCommands,
248
330
  runCommandStats
249
331
  };