claude-code-templates 1.16.1 → 1.17.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.
Files changed (101) hide show
  1. package/README.md +7 -7
  2. package/bin/create-claude-config.js +17 -8
  3. package/package.json +2 -3
  4. package/src/analytics/core/AgentAnalyzer.js +17 -3
  5. package/src/analytics/core/ProcessDetector.js +23 -7
  6. package/src/analytics/core/StateCalculator.js +102 -33
  7. package/src/analytics/data/DataCache.js +7 -7
  8. package/src/analytics-web/chats_mobile.html +2590 -0
  9. package/src/analytics-web/components/App.js +10 -10
  10. package/src/analytics-web/components/SessionTimer.js +1 -1
  11. package/src/analytics-web/components/Sidebar.js +5 -14
  12. package/src/analytics-web/index.html +932 -78
  13. package/src/analytics.js +263 -5
  14. package/src/chats-mobile.js +682 -0
  15. package/src/claude-api-proxy.js +460 -0
  16. package/src/file-operations.js +239 -36
  17. package/src/health-check.js +310 -0
  18. package/src/index.js +1256 -36
  19. package/src/tracking-service.js +31 -34
  20. package/components/agents/api-security-audit.md +0 -92
  21. package/components/agents/database-optimization.md +0 -94
  22. package/components/agents/react-performance-optimization.md +0 -64
  23. package/components/commands/check-file.md +0 -53
  24. package/components/commands/generate-tests.md +0 -68
  25. package/components/mcps/deepgraph-nextjs.json +0 -12
  26. package/components/mcps/deepgraph-react.json +0 -12
  27. package/components/mcps/deepgraph-typescript.json +0 -12
  28. package/components/mcps/deepgraph-vue.json +0 -12
  29. package/components/mcps/filesystem-access.json +0 -12
  30. package/components/mcps/github-integration.json +0 -11
  31. package/components/mcps/memory-integration.json +0 -8
  32. package/components/mcps/mysql-integration.json +0 -11
  33. package/components/mcps/postgresql-integration.json +0 -11
  34. package/components/mcps/web-fetch.json +0 -8
  35. package/src/analytics-web/components/AgentsPage.js +0 -4761
  36. package/templates/common/.claude/commands/git-workflow.md +0 -239
  37. package/templates/common/.claude/commands/project-setup.md +0 -316
  38. package/templates/common/.mcp.json +0 -41
  39. package/templates/common/CLAUDE.md +0 -109
  40. package/templates/common/README.md +0 -96
  41. package/templates/go/.mcp.json +0 -78
  42. package/templates/go/README.md +0 -25
  43. package/templates/javascript-typescript/.claude/commands/api-endpoint.md +0 -51
  44. package/templates/javascript-typescript/.claude/commands/debug.md +0 -52
  45. package/templates/javascript-typescript/.claude/commands/lint.md +0 -48
  46. package/templates/javascript-typescript/.claude/commands/npm-scripts.md +0 -48
  47. package/templates/javascript-typescript/.claude/commands/refactor.md +0 -55
  48. package/templates/javascript-typescript/.claude/commands/test.md +0 -61
  49. package/templates/javascript-typescript/.claude/commands/typescript-migrate.md +0 -51
  50. package/templates/javascript-typescript/.claude/settings.json +0 -142
  51. package/templates/javascript-typescript/.mcp.json +0 -80
  52. package/templates/javascript-typescript/CLAUDE.md +0 -185
  53. package/templates/javascript-typescript/README.md +0 -259
  54. package/templates/javascript-typescript/examples/angular-app/.claude/commands/components.md +0 -63
  55. package/templates/javascript-typescript/examples/angular-app/.claude/commands/services.md +0 -62
  56. package/templates/javascript-typescript/examples/node-api/.claude/commands/api-endpoint.md +0 -46
  57. package/templates/javascript-typescript/examples/node-api/.claude/commands/database.md +0 -56
  58. package/templates/javascript-typescript/examples/node-api/.claude/commands/middleware.md +0 -61
  59. package/templates/javascript-typescript/examples/node-api/.claude/commands/route.md +0 -57
  60. package/templates/javascript-typescript/examples/node-api/CLAUDE.md +0 -102
  61. package/templates/javascript-typescript/examples/react-app/.claude/commands/component.md +0 -29
  62. package/templates/javascript-typescript/examples/react-app/.claude/commands/hooks.md +0 -44
  63. package/templates/javascript-typescript/examples/react-app/.claude/commands/state-management.md +0 -45
  64. package/templates/javascript-typescript/examples/react-app/CLAUDE.md +0 -81
  65. package/templates/javascript-typescript/examples/react-app/agents/react-performance-optimization.md +0 -530
  66. package/templates/javascript-typescript/examples/react-app/agents/react-state-management.md +0 -295
  67. package/templates/javascript-typescript/examples/vue-app/.claude/commands/components.md +0 -46
  68. package/templates/javascript-typescript/examples/vue-app/.claude/commands/composables.md +0 -51
  69. package/templates/python/.claude/commands/lint.md +0 -111
  70. package/templates/python/.claude/commands/test.md +0 -73
  71. package/templates/python/.claude/settings.json +0 -153
  72. package/templates/python/.mcp.json +0 -78
  73. package/templates/python/CLAUDE.md +0 -276
  74. package/templates/python/examples/django-app/.claude/commands/admin.md +0 -264
  75. package/templates/python/examples/django-app/.claude/commands/django-model.md +0 -124
  76. package/templates/python/examples/django-app/.claude/commands/views.md +0 -222
  77. package/templates/python/examples/django-app/CLAUDE.md +0 -313
  78. package/templates/python/examples/django-app/agents/django-api-security.md +0 -642
  79. package/templates/python/examples/django-app/agents/django-database-optimization.md +0 -752
  80. package/templates/python/examples/fastapi-app/.claude/commands/api-endpoints.md +0 -513
  81. package/templates/python/examples/fastapi-app/.claude/commands/auth.md +0 -775
  82. package/templates/python/examples/fastapi-app/.claude/commands/database.md +0 -657
  83. package/templates/python/examples/fastapi-app/.claude/commands/deployment.md +0 -160
  84. package/templates/python/examples/fastapi-app/.claude/commands/testing.md +0 -927
  85. package/templates/python/examples/fastapi-app/CLAUDE.md +0 -229
  86. package/templates/python/examples/flask-app/.claude/commands/app-factory.md +0 -384
  87. package/templates/python/examples/flask-app/.claude/commands/blueprint.md +0 -243
  88. package/templates/python/examples/flask-app/.claude/commands/database.md +0 -410
  89. package/templates/python/examples/flask-app/.claude/commands/deployment.md +0 -620
  90. package/templates/python/examples/flask-app/.claude/commands/flask-route.md +0 -217
  91. package/templates/python/examples/flask-app/.claude/commands/testing.md +0 -559
  92. package/templates/python/examples/flask-app/CLAUDE.md +0 -391
  93. package/templates/ruby/.claude/commands/model.md +0 -360
  94. package/templates/ruby/.claude/commands/test.md +0 -480
  95. package/templates/ruby/.claude/settings.json +0 -146
  96. package/templates/ruby/.mcp.json +0 -83
  97. package/templates/ruby/CLAUDE.md +0 -284
  98. package/templates/ruby/examples/rails-app/.claude/commands/authentication.md +0 -490
  99. package/templates/ruby/examples/rails-app/CLAUDE.md +0 -376
  100. package/templates/rust/.mcp.json +0 -78
  101. package/templates/rust/README.md +0 -26
@@ -0,0 +1,460 @@
1
+ const express = require('express');
2
+ const fs = require('fs-extra');
3
+ const path = require('path');
4
+ const os = require('os');
5
+ const { v4: uuidv4 } = require('uuid');
6
+ const chalk = require('chalk');
7
+
8
+ class ClaudeAPIProxy {
9
+ constructor() {
10
+ this.app = express();
11
+ this.port = 3335;
12
+ this.claudeDir = path.join(os.homedir(), '.claude');
13
+
14
+ // Store active sessions and conversation contexts
15
+ this.activeSessions = new Map();
16
+ this.conversationContexts = new Map();
17
+
18
+ this.setupMiddleware();
19
+ this.setupRoutes();
20
+ }
21
+
22
+ setupMiddleware() {
23
+ this.app.use(express.json());
24
+ this.app.use((req, res, next) => {
25
+ res.header('Access-Control-Allow-Origin', '*');
26
+ res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
27
+ res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
28
+ if (req.method === 'OPTIONS') {
29
+ res.sendStatus(200);
30
+ } else {
31
+ next();
32
+ }
33
+ });
34
+ }
35
+
36
+ setupRoutes() {
37
+ // Get active conversations/sessions
38
+ this.app.get('/api/sessions', async (req, res) => {
39
+ try {
40
+ const sessions = await this.getActiveSessions();
41
+ res.json({ sessions });
42
+ } catch (error) {
43
+ console.error('Error getting sessions:', error);
44
+ res.status(500).json({ error: error.message });
45
+ }
46
+ });
47
+
48
+ // Send message to Claude (main endpoint)
49
+ this.app.post('/api/send-message', async (req, res) => {
50
+ try {
51
+ const { sessionId, message, projectPath } = req.body;
52
+
53
+ if (!sessionId || !message) {
54
+ return res.status(400).json({ error: 'sessionId and message are required' });
55
+ }
56
+
57
+ const result = await this.sendMessageToClaude(sessionId, message, projectPath);
58
+ res.json(result);
59
+
60
+ } catch (error) {
61
+ console.error('Error sending message:', error);
62
+ res.status(500).json({ error: error.message });
63
+ }
64
+ });
65
+
66
+ // Get conversation history
67
+ this.app.get('/api/conversation/:sessionId', async (req, res) => {
68
+ try {
69
+ const { sessionId } = req.params;
70
+ const conversation = await this.getConversationHistory(sessionId);
71
+ res.json({ conversation });
72
+ } catch (error) {
73
+ console.error('Error getting conversation:', error);
74
+ res.status(500).json({ error: error.message });
75
+ }
76
+ });
77
+ }
78
+
79
+ async getActiveSessions() {
80
+ const projectsDir = path.join(this.claudeDir, 'projects');
81
+
82
+ if (!(await fs.pathExists(projectsDir))) {
83
+ return [];
84
+ }
85
+
86
+ const sessions = [];
87
+ const projectDirs = await fs.readdir(projectsDir);
88
+
89
+ for (const projectDir of projectDirs) {
90
+ const projectPath = path.join(projectsDir, projectDir);
91
+ const files = await fs.readdir(projectPath);
92
+
93
+ for (const file of files) {
94
+ if (file.endsWith('.jsonl')) {
95
+ const sessionId = path.basename(file, '.jsonl');
96
+ const filePath = path.join(projectPath, file);
97
+ const stats = await fs.stat(filePath);
98
+
99
+ // Get basic info about the session
100
+ const lastMessage = await this.getLastMessage(filePath);
101
+
102
+ sessions.push({
103
+ sessionId,
104
+ projectPath: this.decodeProjectPath(projectDir),
105
+ filePath,
106
+ lastModified: stats.mtime,
107
+ lastMessage: lastMessage?.content || 'No messages',
108
+ messageCount: await this.getMessageCount(filePath)
109
+ });
110
+ }
111
+ }
112
+ }
113
+
114
+ // Sort by most recent activity
115
+ return sessions.sort((a, b) => new Date(b.lastModified) - new Date(a.lastModified));
116
+ }
117
+
118
+ decodeProjectPath(encodedPath) {
119
+ return encodedPath.replace(/-/g, '/').replace(/^Users/, '/Users');
120
+ }
121
+
122
+ async getLastMessage(filePath) {
123
+ try {
124
+ const content = await fs.readFile(filePath, 'utf8');
125
+ const lines = content.trim().split('\n').filter(line => line.trim());
126
+
127
+ if (lines.length === 0) return null;
128
+
129
+ const lastLine = lines[lines.length - 1];
130
+ const lastMessage = JSON.parse(lastLine);
131
+
132
+ return {
133
+ content: this.extractMessageContent(lastMessage),
134
+ timestamp: lastMessage.timestamp,
135
+ role: lastMessage.message?.role || lastMessage.type
136
+ };
137
+ } catch (error) {
138
+ console.error('Error reading last message:', error);
139
+ return null;
140
+ }
141
+ }
142
+
143
+ async getMessageCount(filePath) {
144
+ try {
145
+ const content = await fs.readFile(filePath, 'utf8');
146
+ const lines = content.trim().split('\n').filter(line => line.trim());
147
+ return lines.length;
148
+ } catch (error) {
149
+ return 0;
150
+ }
151
+ }
152
+
153
+ extractMessageContent(messageObj) {
154
+ if (messageObj.message?.content) {
155
+ if (typeof messageObj.message.content === 'string') {
156
+ return messageObj.message.content;
157
+ }
158
+ if (Array.isArray(messageObj.message.content)) {
159
+ const textContent = messageObj.message.content
160
+ .filter(item => item.type === 'text')
161
+ .map(item => item.text)
162
+ .join(' ');
163
+ return textContent || '[Tool use or other content]';
164
+ }
165
+ }
166
+ return '[No content]';
167
+ }
168
+
169
+ async sendMessageToClaude(sessionId, messageContent, projectPath) {
170
+ console.log(chalk.blue(`📤 Sending message to session ${sessionId}`));
171
+
172
+ // Find the conversation file
173
+ const conversationFile = await this.findConversationFile(sessionId, projectPath);
174
+
175
+ if (!conversationFile) {
176
+ throw new Error(`Conversation file not found for session ${sessionId}`);
177
+ }
178
+
179
+ // Get conversation context
180
+ const context = await this.getConversationContext(conversationFile);
181
+
182
+ // Create user message in Claude Code format
183
+ const userMessage = this.createUserMessage(messageContent, context, sessionId);
184
+
185
+ // Append to JSONL file
186
+ await this.appendToConversation(conversationFile, userMessage);
187
+
188
+ console.log(chalk.green(`✅ Message sent to ${conversationFile}`));
189
+
190
+ // Try to notify Claude Code process about the file change
191
+ await this.notifyClaudeProcess();
192
+
193
+ // TODO: Monitor for Claude Code response
194
+
195
+ return {
196
+ success: true,
197
+ messageId: userMessage.uuid,
198
+ sessionId,
199
+ message: 'Message sent to Claude Code conversation'
200
+ };
201
+ }
202
+
203
+ async findConversationFile(sessionId, projectPath) {
204
+ const projectsDir = path.join(this.claudeDir, 'projects');
205
+
206
+ // If projectPath provided, look there first
207
+ if (projectPath) {
208
+ const encodedPath = this.encodeProjectPath(projectPath);
209
+ const targetDir = path.join(projectsDir, encodedPath);
210
+ const conversationFile = path.join(targetDir, `${sessionId}.jsonl`);
211
+
212
+ if (await fs.pathExists(conversationFile)) {
213
+ return conversationFile;
214
+ }
215
+ }
216
+
217
+ // Otherwise, search all projects
218
+ const projectDirs = await fs.readdir(projectsDir);
219
+
220
+ for (const projectDir of projectDirs) {
221
+ const conversationFile = path.join(projectsDir, projectDir, `${sessionId}.jsonl`);
222
+
223
+ if (await fs.pathExists(conversationFile)) {
224
+ return conversationFile;
225
+ }
226
+ }
227
+
228
+ return null;
229
+ }
230
+
231
+ encodeProjectPath(projectPath) {
232
+ return projectPath.replace(/\\//g, '-').replace(/^-/, '');
233
+ }
234
+
235
+ async getConversationContext(conversationFile) {
236
+ try {
237
+ const content = await fs.readFile(conversationFile, 'utf8');
238
+ const lines = content.trim().split('\n').filter(line => line.trim());
239
+
240
+ if (lines.length === 0) {
241
+ return { lastMessage: null, cwd: process.cwd(), version: '1.0.44' };
242
+ }
243
+
244
+ // Find the last valid JSON line (iterate backwards)
245
+ let lastMessage = null;
246
+ for (let i = lines.length - 1; i >= 0; i--) {
247
+ const line = lines[i].trim();
248
+ try {
249
+ lastMessage = JSON.parse(line);
250
+ break; // Found valid JSON, break out of loop
251
+ } catch (jsonError) {
252
+ // Skip invalid JSON lines
253
+ console.warn(`Skipping invalid JSON line ${i + 1}: ${line.substring(0, 50)}...`);
254
+ continue;
255
+ }
256
+ }
257
+
258
+ if (!lastMessage) {
259
+ console.warn('No valid JSON message found in conversation file');
260
+ return { lastMessage: null, cwd: process.cwd(), version: '1.0.44' };
261
+ }
262
+
263
+ return {
264
+ lastMessage,
265
+ cwd: lastMessage.cwd || process.cwd(),
266
+ version: lastMessage.version || '1.0.44',
267
+ sessionId: lastMessage.sessionId
268
+ };
269
+ } catch (error) {
270
+ console.error('Error getting conversation context:', error);
271
+ return { lastMessage: null, cwd: process.cwd(), version: '1.0.44' };
272
+ }
273
+ }
274
+
275
+ createUserMessage(content, context, sessionId) {
276
+ const uuid = uuidv4();
277
+ const timestamp = new Date().toISOString();
278
+
279
+ return {
280
+ parentUuid: context.lastMessage?.uuid || null,
281
+ isSidechain: false,
282
+ userType: "external",
283
+ cwd: context.cwd,
284
+ sessionId: sessionId,
285
+ version: context.version,
286
+ type: "user",
287
+ message: {
288
+ role: "user",
289
+ content: content
290
+ },
291
+ uuid: uuid,
292
+ timestamp: timestamp
293
+ };
294
+ }
295
+
296
+ async appendToConversation(conversationFile, messageObj) {
297
+ const messageJson = JSON.stringify(messageObj);
298
+ await fs.appendFile(conversationFile, messageJson + '\n');
299
+
300
+ // Force file system change notification by touching the file
301
+ const now = new Date();
302
+ await fs.utimes(conversationFile, now, now);
303
+
304
+ console.log(chalk.green(`📝 Message appended to ${path.basename(conversationFile)}`));
305
+ }
306
+
307
+ async getConversationHistory(sessionId) {
308
+ const conversationFile = await this.findConversationFile(sessionId);
309
+
310
+ if (!conversationFile) {
311
+ throw new Error(`Conversation not found for session ${sessionId}`);
312
+ }
313
+
314
+ const content = await fs.readFile(conversationFile, 'utf8');
315
+ const lines = content.trim().split('\n').filter(line => line.trim());
316
+
317
+ const messages = lines
318
+ .map(line => {
319
+ try {
320
+ return JSON.parse(line);
321
+ } catch (e) {
322
+ return null;
323
+ }
324
+ })
325
+ .filter(msg => msg !== null);
326
+
327
+ return messages;
328
+ }
329
+
330
+ start() {
331
+ return new Promise((resolve) => {
332
+ this.server = this.app.listen(this.port, () => {
333
+ console.log(chalk.green(`🌉 Claude API Proxy running on http://localhost:${this.port}`));
334
+ console.log(chalk.blue(`📡 Ready to intercept and send messages to Claude Code`));
335
+ resolve();
336
+ });
337
+ });
338
+ }
339
+
340
+ stop() {
341
+ if (this.server) {
342
+ this.server.close();
343
+ console.log(chalk.yellow(`🔌 Claude API Proxy stopped`));
344
+ }
345
+ }
346
+ }
347
+
348
+ module.exports = ClaudeAPIProxy;
349
+
350
+ // Method to notify Claude Code process
351
+ ClaudeAPIProxy.prototype.notifyClaudeProcess = async function() {
352
+ try {
353
+ console.log(chalk.blue('🔔 Attempting to activate Claude Code process...'));
354
+
355
+ // Method 1: Find Claude Code process and try to send input
356
+ const { exec, spawn } = require('child_process');
357
+
358
+ // First, find Claude Code processes
359
+ exec('ps aux | grep "claude"', (error, stdout, stderr) => {
360
+ if (stdout) {
361
+ const claudeProcesses = stdout.split('\n')
362
+ .filter(line => line.includes('claude') && !line.includes('grep'))
363
+ .filter(line => !line.includes('claude-code-templates')); // Exclude our dashboard
364
+
365
+ console.log(chalk.blue(`🔍 Found ${claudeProcesses.length} Claude process(es)`));
366
+
367
+ claudeProcesses.forEach(processLine => {
368
+ const pid = processLine.trim().split(/\s+/)[1];
369
+ console.log(chalk.gray(` - PID ${pid}: ${processLine.substring(0, 100)}...`));
370
+ });
371
+ }
372
+ });
373
+
374
+ // Method 2: Try to write to the Claude Code terminal using applescript (macOS)
375
+ if (process.platform === 'darwin') {
376
+ this.tryAppleScriptNotification();
377
+ }
378
+
379
+ // Method 3: Try sending wake-up signal
380
+ try {
381
+ exec('pkill -SIGUSR1 claude', () => {});
382
+ } catch (e) {/* ignore */}
383
+
384
+ } catch (error) {
385
+ console.log(chalk.gray('🔕 Could not notify Claude Code process'));
386
+ }
387
+ };
388
+
389
+ // Try to use AppleScript to send input to Claude Code terminal
390
+ ClaudeAPIProxy.prototype.tryAppleScriptNotification = function() {
391
+ try {
392
+ const { exec } = require('child_process');
393
+
394
+ // This AppleScript tries to find Terminal/iTerm with Claude Code and send a key
395
+ const appleScript = `
396
+ tell application "System Events"
397
+ set claudeFound to false
398
+ try
399
+ -- Try Terminal first
400
+ tell application "Terminal"
401
+ repeat with w in windows
402
+ repeat with t in tabs of w
403
+ if (custom title of t contains "claude" or name of t contains "claude") then
404
+ set claudeFound to true
405
+ set frontmost to true
406
+ do script "" in t -- Send empty command to wake up
407
+ exit repeat
408
+ end if
409
+ end repeat
410
+ if claudeFound then exit repeat
411
+ end repeat
412
+ end tell
413
+ end try
414
+
415
+ if not claudeFound then
416
+ try
417
+ -- Try iTerm2
418
+ tell application "iTerm"
419
+ repeat with w in windows
420
+ repeat with t in tabs of w
421
+ tell current session of t
422
+ if (name contains "claude") then
423
+ set claudeFound to true
424
+ select
425
+ write text ""
426
+ exit repeat
427
+ end if
428
+ end tell
429
+ end repeat
430
+ if claudeFound then exit repeat
431
+ end repeat
432
+ end tell
433
+ end try
434
+ end if
435
+ end tell
436
+ `;
437
+
438
+ exec(`osascript -e '${appleScript.replace(/'/g, "\\'")}'`, (error) => {
439
+ if (error) {
440
+ console.log(chalk.gray('🔕 AppleScript notification failed'));
441
+ } else {
442
+ console.log(chalk.green('✅ AppleScript notification sent'));
443
+ }
444
+ });
445
+
446
+ } catch (error) {
447
+ // Silent fail
448
+ }
449
+ };
450
+
451
+ // If run directly
452
+ if (require.main === module) {
453
+ const proxy = new ClaudeAPIProxy();
454
+ proxy.start();
455
+
456
+ process.on('SIGINT', () => {
457
+ proxy.stop();
458
+ process.exit(0);
459
+ });
460
+ }