claude-code-templates 1.19.1 → 1.20.0

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/README.md CHANGED
@@ -28,6 +28,7 @@ npx claude-code-templates@latest --health-check
28
28
  - **šŸ“Š Real-time Analytics** - Monitor Claude Code sessions with live state detection and performance metrics
29
29
  - **šŸ” Health Check** - Comprehensive system validation with actionable recommendations
30
30
  - **🧩 Individual Components** - Install specialized agents, commands, and MCPs individually
31
+ - **šŸŒ Global Agents** - Create AI agents accessible from anywhere using Claude Code SDK
31
32
 
32
33
  ## šŸŽÆ What You Get
33
34
 
@@ -49,6 +50,51 @@ npx claude-code-templates@latest --health-check
49
50
  | **Go** | Gin, Echo, Fiber | 🚧 Coming Soon |
50
51
  | **Rust** | Axum, Warp, Actix | 🚧 Coming Soon |
51
52
 
53
+ ## šŸŒ Global Agents (Claude Code SDK Integration)
54
+
55
+ Create AI agents that can be executed from anywhere using the Claude Code SDK:
56
+
57
+ ```bash
58
+ # Create a global agent (one-time setup)
59
+ npx claude-code-templates@latest --create-agent customer-support
60
+
61
+ # Use the agent from anywhere
62
+ customer-support "Help me with ticket #12345"
63
+ sre-logs "Analyze error patterns in app.log"
64
+ code-reviewer "Review this PR for security issues"
65
+ ```
66
+
67
+ ### Available Global Agents
68
+
69
+ | Agent | Usage | Description |
70
+ |-------|-------|-------------|
71
+ | `customer-support` | `customer-support "query"` | AI customer support specialist |
72
+ | `api-security-audit` | `api-security-audit "analyze endpoints"` | Security auditing for APIs |
73
+ | `react-performance-optimization` | `react-performance-optimization "optimize components"` | React performance expert |
74
+ | `database-optimization` | `database-optimization "improve queries"` | Database performance tuning |
75
+
76
+ ### Global Agent Management
77
+
78
+ ```bash
79
+ # List installed global agents
80
+ npx claude-code-templates@latest --list-agents
81
+
82
+ # Update an agent to latest version
83
+ npx claude-code-templates@latest --update-agent customer-support
84
+
85
+ # Remove an agent
86
+ npx claude-code-templates@latest --remove-agent customer-support
87
+ ```
88
+
89
+ ### How It Works
90
+
91
+ 1. **Download Agent**: Fetches the latest agent from GitHub
92
+ 2. **Generate Executable**: Creates a Node.js script that calls Claude Code SDK
93
+ 3. **Add to PATH**: Makes the agent available globally in your shell
94
+ 4. **Ready to Use**: Execute `agent-name "your prompt"` from any directory
95
+
96
+ The agents use the Claude Code SDK internally to provide specialized AI assistance with domain-specific knowledge and best practices.
97
+
52
98
  ## šŸ“– Documentation
53
99
 
54
100
  **[šŸ“š Complete Documentation](https://docs.aitmpl.com/)** - Comprehensive guides, examples, and API reference
@@ -41,7 +41,7 @@ console.log(
41
41
 
42
42
  program
43
43
  .name('create-claude-config')
44
- .description('Setup Claude Code configurations for different programming languages')
44
+ .description('Setup Claude Code configurations and create global AI agents powered by Claude Code SDK')
45
45
  .version(require('../package.json').version)
46
46
  .option('-l, --language <language>', 'specify programming language (deprecated, use --template)')
47
47
  .option('-f, --framework <framework>', 'specify framework (deprecated, use --template)')
@@ -66,6 +66,10 @@ program
66
66
  .option('--hook <hook>', 'install specific hook component (supports comma-separated values)')
67
67
  .option('--workflow <workflow>', 'install workflow from hash (#hash) OR workflow YAML (base64 encoded) when used with --agent/--command/--mcp')
68
68
  .option('--prompt <prompt>', 'execute the provided prompt in Claude Code after installation')
69
+ .option('--create-agent <agent>', 'create a global agent accessible from anywhere (e.g., customer-support)')
70
+ .option('--list-agents', 'list all installed global agents')
71
+ .option('--remove-agent <agent>', 'remove a global agent')
72
+ .option('--update-agent <agent>', 'update a global agent to the latest version')
69
73
  .action(async (options) => {
70
74
  try {
71
75
  await createClaudeConfig(options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-templates",
3
- "version": "1.19.1",
3
+ "version": "1.20.0",
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": {
package/src/index.js CHANGED
@@ -16,6 +16,7 @@ const { runAnalytics } = require('./analytics');
16
16
  const { startChatsMobile } = require('./chats-mobile');
17
17
  const { runHealthCheck } = require('./health-check');
18
18
  const { trackingService } = require('./tracking-service');
19
+ const { createGlobalAgent, listGlobalAgents, removeGlobalAgent, updateGlobalAgent } = require('./sdk/global-agent-manager');
19
20
 
20
21
  async function showMainMenu() {
21
22
  console.log('');
@@ -130,6 +131,30 @@ async function createClaudeConfig(options = {}) {
130
131
  return;
131
132
  }
132
133
 
134
+ // Handle global agent creation
135
+ if (options.createAgent) {
136
+ await createGlobalAgent(options.createAgent, options);
137
+ return;
138
+ }
139
+
140
+ // Handle global agent listing
141
+ if (options.listAgents) {
142
+ await listGlobalAgents(options);
143
+ return;
144
+ }
145
+
146
+ // Handle global agent removal
147
+ if (options.removeAgent) {
148
+ await removeGlobalAgent(options.removeAgent, options);
149
+ return;
150
+ }
151
+
152
+ // Handle global agent update
153
+ if (options.updateAgent) {
154
+ await updateGlobalAgent(options.updateAgent, options);
155
+ return;
156
+ }
157
+
133
158
  // Handle command stats analysis (both singular and plural)
134
159
  if (options.commandStats || options.commandsStats) {
135
160
  await runCommandStats(options);
@@ -0,0 +1,626 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const os = require('os');
4
+ const chalk = require('chalk');
5
+ const ora = require('ora');
6
+
7
+ // Global agents directory
8
+ const GLOBAL_AGENTS_DIR = path.join(os.homedir(), '.claude-code-templates');
9
+ const AGENTS_DIR = path.join(GLOBAL_AGENTS_DIR, 'agents');
10
+ const LOCAL_BIN_DIR = path.join(GLOBAL_AGENTS_DIR, 'bin');
11
+
12
+ // Try to use system bin directory for immediate availability
13
+ const SYSTEM_BIN_DIR = '/usr/local/bin';
14
+ const isSystemWritable = () => {
15
+ try {
16
+ const testFile = path.join(SYSTEM_BIN_DIR, '.test-write');
17
+ require('fs').writeFileSync(testFile, 'test', 'utf8');
18
+ require('fs').unlinkSync(testFile);
19
+ return true;
20
+ } catch (error) {
21
+ return false;
22
+ }
23
+ };
24
+
25
+ // Choose the best bin directory
26
+ const BIN_DIR = isSystemWritable() ? SYSTEM_BIN_DIR : LOCAL_BIN_DIR;
27
+
28
+ /**
29
+ * Create a global agent that can be executed from anywhere
30
+ */
31
+ async function createGlobalAgent(agentName, options = {}) {
32
+ console.log(chalk.blue(`šŸ¤– Creating global agent: ${agentName}`));
33
+
34
+ try {
35
+ // Ensure directories exist
36
+ await fs.ensureDir(AGENTS_DIR);
37
+ await fs.ensureDir(LOCAL_BIN_DIR); // Always ensure local bin exists for backups
38
+
39
+ if (BIN_DIR === SYSTEM_BIN_DIR) {
40
+ console.log(chalk.green('šŸŒ Installing to system directory (immediately available)'));
41
+ } else {
42
+ console.log(chalk.yellow('āš ļø Installing to user directory (requires PATH setup)'));
43
+ await fs.ensureDir(BIN_DIR);
44
+ }
45
+
46
+ // Download agent from GitHub
47
+ const spinner = ora('Downloading agent from GitHub...').start();
48
+
49
+ let githubUrl;
50
+ if (agentName.includes('/')) {
51
+ // Category/agent format
52
+ githubUrl = `https://raw.githubusercontent.com/davila7/claude-code-templates/main/cli-tool/components/agents/${agentName}.md`;
53
+ } else {
54
+ // Direct agent format - try to find it in any category
55
+ githubUrl = await findAgentUrl(agentName);
56
+ if (!githubUrl) {
57
+ spinner.fail(`Agent "${agentName}" not found`);
58
+ await showAvailableAgents();
59
+ return;
60
+ }
61
+ }
62
+
63
+ const response = await fetch(githubUrl);
64
+ if (!response.ok) {
65
+ spinner.fail(`Failed to download agent: HTTP ${response.status}`);
66
+ if (response.status === 404) {
67
+ await showAvailableAgents();
68
+ }
69
+ return;
70
+ }
71
+
72
+ const agentContent = await response.text();
73
+ spinner.succeed('Agent downloaded successfully');
74
+
75
+ // Extract agent name for file/executable naming
76
+ const executableName = agentName.includes('/') ?
77
+ agentName.split('/')[1] : agentName;
78
+
79
+ // Save agent content
80
+ const agentFile = path.join(AGENTS_DIR, `${executableName}.md`);
81
+ await fs.writeFile(agentFile, agentContent, 'utf8');
82
+
83
+ // Generate executable script
84
+ await generateExecutableScript(executableName, agentFile);
85
+
86
+ console.log(chalk.green(`āœ… Global agent '${executableName}' created successfully!`));
87
+ console.log(chalk.cyan('šŸ“¦ Usage:'));
88
+ console.log(chalk.white(` ${executableName} "your prompt here"`));
89
+
90
+ if (BIN_DIR === SYSTEM_BIN_DIR) {
91
+ console.log(chalk.green('šŸŽ‰ Ready to use immediately! No setup required.'));
92
+ console.log(chalk.gray('šŸ’” Works in scripts, npm tasks, CI/CD, etc.'));
93
+ } else {
94
+ // Add to PATH (first time setup) only for user directory
95
+ await addToPath();
96
+ console.log(chalk.yellow('šŸ”„ Restart your terminal or run:'));
97
+ console.log(chalk.gray(' source ~/.bashrc # for bash'));
98
+ console.log(chalk.gray(' source ~/.zshrc # for zsh'));
99
+ }
100
+
101
+ } catch (error) {
102
+ console.log(chalk.red(`āŒ Error creating global agent: ${error.message}`));
103
+ }
104
+ }
105
+
106
+ /**
107
+ * List installed global agents
108
+ */
109
+ async function listGlobalAgents(options = {}) {
110
+ console.log(chalk.blue('šŸ“‹ Installed Global Agents:'));
111
+
112
+ try {
113
+ // Check both system and local bin directories
114
+ let systemAgents = [];
115
+ if (await fs.pathExists(SYSTEM_BIN_DIR)) {
116
+ const systemFiles = await fs.readdir(SYSTEM_BIN_DIR);
117
+ for (const file of systemFiles) {
118
+ if (!file.startsWith('.') && await fs.pathExists(path.join(AGENTS_DIR, `${file}.md`))) {
119
+ systemAgents.push(file);
120
+ }
121
+ }
122
+ }
123
+
124
+ const localAgents = await fs.pathExists(LOCAL_BIN_DIR) ?
125
+ (await fs.readdir(LOCAL_BIN_DIR)).filter(file => !file.startsWith('.')) : [];
126
+
127
+ const allAgents = [...new Set([...systemAgents, ...localAgents])];
128
+
129
+ if (allAgents.length === 0) {
130
+ console.log(chalk.yellow('āš ļø No global agents installed yet.'));
131
+ console.log(chalk.gray('šŸ’” Create one with: npx claude-code-templates@latest --create-agent <agent-name>'));
132
+ return;
133
+ }
134
+
135
+ console.log(chalk.green(`\nāœ… Found ${allAgents.length} global agent(s):\n`));
136
+
137
+ for (const agent of allAgents) {
138
+ // Check which directory has the agent
139
+ const systemPath = path.join(SYSTEM_BIN_DIR, agent);
140
+ const localPath = path.join(LOCAL_BIN_DIR, agent);
141
+
142
+ let agentPath, location;
143
+ if (await fs.pathExists(systemPath)) {
144
+ agentPath = systemPath;
145
+ location = 'šŸŒ system';
146
+ } else {
147
+ agentPath = localPath;
148
+ location = 'šŸ‘¤ user';
149
+ }
150
+
151
+ const stats = await fs.stat(agentPath);
152
+ const isExecutable = (stats.mode & parseInt('111', 8)) !== 0;
153
+
154
+ console.log(chalk.cyan(` ${isExecutable ? 'āœ…' : 'āŒ'} ${agent} (${location})`));
155
+ console.log(chalk.gray(` Usage: ${agent} "your prompt"`));
156
+ console.log(chalk.gray(` Created: ${stats.birthtime.toLocaleDateString()}`));
157
+ console.log('');
158
+ }
159
+
160
+ console.log(chalk.blue('🌟 Global Usage:'));
161
+ console.log(chalk.gray(' • Run from any directory: <agent-name> "prompt"'));
162
+ console.log(chalk.gray(' • List agents: npx claude-code-templates@latest --list-agents'));
163
+ console.log(chalk.gray(' • Remove agent: npx claude-code-templates@latest --remove-agent <name>'));
164
+
165
+ } catch (error) {
166
+ console.log(chalk.red(`āŒ Error listing agents: ${error.message}`));
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Remove a global agent
172
+ */
173
+ async function removeGlobalAgent(agentName, options = {}) {
174
+ console.log(chalk.blue(`šŸ—‘ļø Removing global agent: ${agentName}`));
175
+
176
+ try {
177
+ const systemExecutablePath = path.join(SYSTEM_BIN_DIR, agentName);
178
+ const localExecutablePath = path.join(LOCAL_BIN_DIR, agentName);
179
+ const agentPath = path.join(AGENTS_DIR, `${agentName}.md`);
180
+
181
+ let removed = false;
182
+
183
+ // Remove from system directory
184
+ if (await fs.pathExists(systemExecutablePath)) {
185
+ await fs.remove(systemExecutablePath);
186
+ console.log(chalk.green(`āœ… Removed system executable: ${agentName}`));
187
+ removed = true;
188
+ }
189
+
190
+ // Remove from local directory
191
+ if (await fs.pathExists(localExecutablePath)) {
192
+ await fs.remove(localExecutablePath);
193
+ console.log(chalk.green(`āœ… Removed local executable: ${agentName}`));
194
+ removed = true;
195
+ }
196
+
197
+ // Remove agent file
198
+ if (await fs.pathExists(agentPath)) {
199
+ await fs.remove(agentPath);
200
+ console.log(chalk.green(`āœ… Removed agent file: ${agentName}.md`));
201
+ removed = true;
202
+ }
203
+
204
+ if (!removed) {
205
+ console.log(chalk.yellow(`āš ļø Agent '${agentName}' not found.`));
206
+ console.log(chalk.gray('šŸ’” List available agents with: --list-agents'));
207
+ return;
208
+ }
209
+
210
+ console.log(chalk.green(`šŸŽ‰ Global agent '${agentName}' removed successfully!`));
211
+
212
+ } catch (error) {
213
+ console.log(chalk.red(`āŒ Error removing agent: ${error.message}`));
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Update a global agent
219
+ */
220
+ async function updateGlobalAgent(agentName, options = {}) {
221
+ console.log(chalk.blue(`šŸ”„ Updating global agent: ${agentName}`));
222
+
223
+ try {
224
+ const executablePath = path.join(BIN_DIR, agentName);
225
+
226
+ if (!await fs.pathExists(executablePath)) {
227
+ console.log(chalk.yellow(`āš ļø Agent '${agentName}' not found.`));
228
+ console.log(chalk.gray('šŸ’” Create it with: --create-agent <agent-name>'));
229
+ return;
230
+ }
231
+
232
+ // Re-download and recreate
233
+ console.log(chalk.gray('šŸ”„ Re-downloading latest version...'));
234
+ await createGlobalAgent(agentName, { ...options, update: true });
235
+
236
+ } catch (error) {
237
+ console.log(chalk.red(`āŒ Error updating agent: ${error.message}`));
238
+ }
239
+ }
240
+
241
+ /**
242
+ * Generate executable script for an agent
243
+ */
244
+ async function generateExecutableScript(agentName, agentFile) {
245
+ const scriptContent = `#!/usr/bin/env node
246
+
247
+ const { execSync } = require('child_process');
248
+ const path = require('path');
249
+ const fs = require('fs');
250
+
251
+ // Check if Claude CLI is available
252
+ function checkClaudeCLI() {
253
+ try {
254
+ execSync('claude --version', { stdio: 'ignore' });
255
+ return true;
256
+ } catch (error) {
257
+ return false;
258
+ }
259
+ }
260
+
261
+ // Read agent system prompt
262
+ const agentPath = '${agentFile}';
263
+ if (!fs.existsSync(agentPath)) {
264
+ console.error('āŒ Agent file not found:', agentPath);
265
+ process.exit(1);
266
+ }
267
+
268
+ const systemPrompt = fs.readFileSync(agentPath, 'utf8');
269
+
270
+ // Parse arguments and detect context
271
+ const args = process.argv.slice(2);
272
+ let userInput = '';
273
+ let explicitFiles = [];
274
+ let explicitDirs = [];
275
+ let autoDetect = true;
276
+
277
+ // Parse command line arguments
278
+ for (let i = 0; i < args.length; i++) {
279
+ const arg = args[i];
280
+
281
+ if (arg === '--file' && i + 1 < args.length) {
282
+ explicitFiles.push(args[++i]);
283
+ autoDetect = false; // Disable auto-detect when explicit files provided
284
+ } else if (arg === '--dir' && i + 1 < args.length) {
285
+ explicitDirs.push(args[++i]);
286
+ autoDetect = false;
287
+ } else if (arg === '--no-auto') {
288
+ autoDetect = false;
289
+ } else if (arg === '--help' || arg === '-h') {
290
+ console.log('Usage: ${agentName} [options] "your prompt"');
291
+ console.log('');
292
+ console.log('Context Options:');
293
+ console.log(' [default] Auto-detect project files (smart context)');
294
+ console.log(' --file <path> Include specific file');
295
+ console.log(' --dir <path> Include specific directory');
296
+ console.log(' --no-auto Disable auto-detection');
297
+ console.log('');
298
+ console.log('Examples:');
299
+ console.log(' ${agentName} "review for security issues" # Auto-detect');
300
+ console.log(' ${agentName} --file auth.js "check this file" # Specific file');
301
+ console.log(' ${agentName} --no-auto "general advice" # No context');
302
+ process.exit(0);
303
+ } else if (!arg.startsWith('--')) {
304
+ userInput += arg + ' ';
305
+ }
306
+ }
307
+
308
+ userInput = userInput.trim();
309
+
310
+ if (!userInput) {
311
+ console.error('āŒ Please provide a prompt');
312
+ console.error('Usage: ${agentName} [options] "your prompt"');
313
+ process.exit(1);
314
+ }
315
+
316
+ // Auto-detect project context if enabled
317
+ let contextPrompt = '';
318
+ if (autoDetect && explicitFiles.length === 0 && explicitDirs.length === 0) {
319
+ const fs = require('fs');
320
+ const path = require('path');
321
+ const cwd = process.cwd();
322
+
323
+ // Detect project type and relevant files
324
+ let projectType = 'unknown';
325
+ let relevantFiles = [];
326
+
327
+ // Check for common project indicators
328
+ if (fs.existsSync('package.json')) {
329
+ projectType = 'javascript/node';
330
+ const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
331
+
332
+ // Add framework detection
333
+ if (packageJson.dependencies?.react || packageJson.devDependencies?.react) {
334
+ projectType = 'react';
335
+ } else if (packageJson.dependencies?.vue || packageJson.devDependencies?.vue) {
336
+ projectType = 'vue';
337
+ } else if (packageJson.dependencies?.next || packageJson.devDependencies?.next) {
338
+ projectType = 'nextjs';
339
+ }
340
+
341
+ // Common files to include for JS projects
342
+ const jsFiles = ['src/', 'lib/', 'components/', 'pages/', 'api/', 'routes/'];
343
+ jsFiles.forEach(dir => {
344
+ if (fs.existsSync(dir)) relevantFiles.push(dir);
345
+ });
346
+
347
+ } else if (fs.existsSync('requirements.txt') || fs.existsSync('pyproject.toml')) {
348
+ projectType = 'python';
349
+ relevantFiles = ['*.py', 'src/', 'app/', 'api/'];
350
+
351
+ } else if (fs.existsSync('Cargo.toml')) {
352
+ projectType = 'rust';
353
+ relevantFiles = ['src/', 'Cargo.toml'];
354
+
355
+ } else if (fs.existsSync('go.mod')) {
356
+ projectType = 'go';
357
+ relevantFiles = ['*.go', 'cmd/', 'internal/', 'pkg/'];
358
+ }
359
+
360
+ // Build context prompt
361
+ if (projectType !== 'unknown') {
362
+ contextPrompt = \`
363
+
364
+ šŸ“ PROJECT CONTEXT:
365
+ - Project type: \${projectType}
366
+ - Working directory: \${path.basename(cwd)}
367
+ - Auto-detected relevant files/folders: \${relevantFiles.join(', ')}
368
+
369
+ Please analyze the \${userInput} in the context of this \${projectType} project. You have access to read any files in the current directory using the Read tool.\`;
370
+ }
371
+ }
372
+
373
+ // Check Claude CLI availability
374
+ if (!checkClaudeCLI()) {
375
+ console.error('āŒ Claude CLI not found in PATH');
376
+ console.error('šŸ’” Install Claude CLI: https://claude.ai/code');
377
+ console.error('šŸ’” Or install via npm: npm install -g @anthropic-ai/claude-code');
378
+ process.exit(1);
379
+ }
380
+
381
+ // Escape quotes in system prompt for shell execution
382
+ const escapedSystemPrompt = systemPrompt.replace(/"/g, '\\\\"').replace(/\`/g, '\\\\\`');
383
+
384
+ // Build final prompt with context
385
+ const finalPrompt = userInput + contextPrompt;
386
+ const escapedFinalPrompt = finalPrompt.replace(/"/g, '\\\\"').replace(/\`/g, '\\\\\`');
387
+
388
+ // Build Claude command with SDK
389
+ const claudeCmd = \`claude -p "\${escapedFinalPrompt}" --append-system-prompt "\${escapedSystemPrompt}"\`;
390
+
391
+ // Show loading indicator
392
+ const frames = ['ā ‹', 'ā ™', 'ā ¹', 'ā ø', 'ā ¼', 'ā “', 'ā ¦', 'ā §', 'ā ‡', 'ā '];
393
+ let currentFrame = 0;
394
+ const agentDisplayName = '${agentName}'.replace(/-/g, ' ').replace(/\\b\\w/g, l => l.toUpperCase());
395
+
396
+ console.error(\`\\nšŸ¤– \${agentDisplayName} is thinking...\`);
397
+ const loader = setInterval(() => {
398
+ process.stderr.write(\`\\r\${frames[currentFrame]} Claude Code is working... \`);
399
+ currentFrame = (currentFrame + 1) % frames.length;
400
+ }, 100);
401
+
402
+ try {
403
+ // Execute Claude with the agent's system prompt
404
+ execSync(claudeCmd, {
405
+ stdio: ['inherit', 'inherit', 'pipe'],
406
+ cwd: process.cwd()
407
+ });
408
+
409
+ // Clear loader
410
+ clearInterval(loader);
411
+ process.stderr.write('\\rāœ… Response ready!\\n\\n');
412
+
413
+ } catch (error) {
414
+ clearInterval(loader);
415
+ process.stderr.write('\\r');
416
+ console.error('āŒ Error executing Claude:', error.message);
417
+ process.exit(1);
418
+ }
419
+ `;
420
+
421
+ const scriptPath = path.join(BIN_DIR, agentName);
422
+ await fs.writeFile(scriptPath, scriptContent, 'utf8');
423
+
424
+ // Make executable (Unix/Linux/macOS)
425
+ if (process.platform !== 'win32') {
426
+ await fs.chmod(scriptPath, 0o755);
427
+ }
428
+ }
429
+
430
+ /**
431
+ * Add global agents bin directory to PATH
432
+ */
433
+ async function addToPath() {
434
+ const shell = process.env.SHELL || '';
435
+ const isWindows = process.platform === 'win32';
436
+
437
+ if (isWindows) {
438
+ // Windows PATH management
439
+ console.log(chalk.yellow('🪟 Windows detected:'));
440
+ console.log(chalk.gray(`Add this to your PATH: ${BIN_DIR}`));
441
+ console.log(chalk.gray('Or run this in PowerShell as Administrator:'));
442
+ console.log(chalk.white(`[Environment]::SetEnvironmentVariable("Path", $env:Path + ";${BIN_DIR}", "User")`));
443
+ return;
444
+ }
445
+
446
+ // Unix-like systems
447
+ const pathExport = `export PATH="${BIN_DIR}:$PATH"`;
448
+
449
+ // Determine shell config files to update
450
+ const configFiles = [];
451
+
452
+ if (shell.includes('bash') || !shell) {
453
+ configFiles.push(path.join(os.homedir(), '.bashrc'));
454
+ configFiles.push(path.join(os.homedir(), '.bash_profile'));
455
+ }
456
+
457
+ if (shell.includes('zsh')) {
458
+ configFiles.push(path.join(os.homedir(), '.zshrc'));
459
+ }
460
+
461
+ if (shell.includes('fish')) {
462
+ const fishConfigDir = path.join(os.homedir(), '.config', 'fish');
463
+ await fs.ensureDir(fishConfigDir);
464
+ configFiles.push(path.join(fishConfigDir, 'config.fish'));
465
+ }
466
+
467
+ // Add default files if shell not detected
468
+ if (configFiles.length === 0) {
469
+ configFiles.push(path.join(os.homedir(), '.bashrc'));
470
+ configFiles.push(path.join(os.homedir(), '.zshrc'));
471
+ }
472
+
473
+ // Check if PATH is already added
474
+ let alreadyInPath = false;
475
+
476
+ for (const configFile of configFiles) {
477
+ if (await fs.pathExists(configFile)) {
478
+ const content = await fs.readFile(configFile, 'utf8');
479
+ if (content.includes(BIN_DIR)) {
480
+ alreadyInPath = true;
481
+ break;
482
+ }
483
+ }
484
+ }
485
+
486
+ if (alreadyInPath) {
487
+ console.log(chalk.green('āœ… PATH already configured'));
488
+ return;
489
+ }
490
+
491
+ // Add to PATH in config files
492
+ console.log(chalk.blue('šŸ”§ Adding to PATH...'));
493
+
494
+ for (const configFile of configFiles) {
495
+ try {
496
+ let content = '';
497
+ if (await fs.pathExists(configFile)) {
498
+ content = await fs.readFile(configFile, 'utf8');
499
+ }
500
+
501
+ // Add PATH export if not already present
502
+ if (!content.includes(BIN_DIR)) {
503
+ const newContent = content + `\n# Claude Code Templates - Global Agents\n${pathExport}\n`;
504
+ await fs.writeFile(configFile, newContent, 'utf8');
505
+ console.log(chalk.green(`āœ… Updated ${path.basename(configFile)}`));
506
+ }
507
+ } catch (error) {
508
+ console.log(chalk.yellow(`āš ļø Could not update ${configFile}: ${error.message}`));
509
+ }
510
+ }
511
+ }
512
+
513
+ /**
514
+ * Find agent URL by searching in all categories
515
+ */
516
+ async function findAgentUrl(agentName) {
517
+ try {
518
+ // First try root level
519
+ const rootUrl = `https://raw.githubusercontent.com/davila7/claude-code-templates/main/cli-tool/components/agents/${agentName}.md`;
520
+ const rootResponse = await fetch(rootUrl);
521
+ if (rootResponse.ok) {
522
+ return rootUrl;
523
+ }
524
+
525
+ // Search in categories
526
+ const categoriesResponse = await fetch('https://api.github.com/repos/davila7/claude-code-templates/contents/cli-tool/components/agents');
527
+ if (!categoriesResponse.ok) {
528
+ return null;
529
+ }
530
+
531
+ const contents = await categoriesResponse.json();
532
+
533
+ for (const item of contents) {
534
+ if (item.type === 'dir') {
535
+ const categoryUrl = `https://raw.githubusercontent.com/davila7/claude-code-templates/main/cli-tool/components/agents/${item.name}/${agentName}.md`;
536
+ try {
537
+ const categoryResponse = await fetch(categoryUrl);
538
+ if (categoryResponse.ok) {
539
+ return categoryUrl;
540
+ }
541
+ } catch (error) {
542
+ // Continue searching
543
+ }
544
+ }
545
+ }
546
+
547
+ return null;
548
+ } catch (error) {
549
+ return null;
550
+ }
551
+ }
552
+
553
+ /**
554
+ * Show available agents for user selection
555
+ */
556
+ async function showAvailableAgents() {
557
+ console.log(chalk.yellow('\nšŸ“‹ Available Agents:'));
558
+ console.log(chalk.gray('Use format: category/agent-name or just agent-name\n'));
559
+
560
+ try {
561
+ const response = await fetch('https://api.github.com/repos/davila7/claude-code-templates/contents/cli-tool/components/agents');
562
+ if (!response.ok) {
563
+ console.log(chalk.red('āŒ Could not fetch available agents from GitHub'));
564
+ return;
565
+ }
566
+
567
+ const contents = await response.json();
568
+ const agents = [];
569
+
570
+ for (const item of contents) {
571
+ if (item.type === 'file' && item.name.endsWith('.md')) {
572
+ agents.push({ name: item.name.replace('.md', ''), category: 'root' });
573
+ } else if (item.type === 'dir') {
574
+ try {
575
+ const categoryResponse = await fetch(`https://api.github.com/repos/davila7/claude-code-templates/contents/cli-tool/components/agents/${item.name}`);
576
+ if (categoryResponse.ok) {
577
+ const categoryContents = await categoryResponse.json();
578
+ for (const categoryItem of categoryContents) {
579
+ if (categoryItem.type === 'file' && categoryItem.name.endsWith('.md')) {
580
+ agents.push({
581
+ name: categoryItem.name.replace('.md', ''),
582
+ category: item.name,
583
+ path: `${item.name}/${categoryItem.name.replace('.md', '')}`
584
+ });
585
+ }
586
+ }
587
+ }
588
+ } catch (error) {
589
+ // Skip category on error
590
+ }
591
+ }
592
+ }
593
+
594
+ // Group by category
595
+ const grouped = agents.reduce((acc, agent) => {
596
+ const category = agent.category === 'root' ? 'šŸ¤– General' : `šŸ“ ${agent.category}`;
597
+ if (!acc[category]) acc[category] = [];
598
+ acc[category].push(agent);
599
+ return acc;
600
+ }, {});
601
+
602
+ Object.entries(grouped).forEach(([category, categoryAgents]) => {
603
+ console.log(chalk.cyan(category));
604
+ categoryAgents.forEach(agent => {
605
+ const displayName = agent.path || agent.name;
606
+ console.log(chalk.gray(` • ${displayName}`));
607
+ });
608
+ console.log('');
609
+ });
610
+
611
+ console.log(chalk.blue('Examples:'));
612
+ console.log(chalk.gray(' npx claude-code-templates@latest --create-agent api-security-audit'));
613
+ console.log(chalk.gray(' npx claude-code-templates@latest --create-agent deep-research-team/academic-researcher'));
614
+
615
+ } catch (error) {
616
+ console.log(chalk.red('āŒ Error fetching agents:', error.message));
617
+ }
618
+ }
619
+
620
+ module.exports = {
621
+ createGlobalAgent,
622
+ listGlobalAgents,
623
+ removeGlobalAgent,
624
+ updateGlobalAgent,
625
+ showAvailableAgents
626
+ };