claude-mpm 4.2.1__py3-none-any.whl → 4.2.3__py3-none-any.whl
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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/templates/agent-manager.json +1 -1
- claude_mpm/agents/templates/agentic_coder_optimizer.json +1 -1
- claude_mpm/agents/templates/api_qa.json +1 -1
- claude_mpm/agents/templates/code_analyzer.json +1 -1
- claude_mpm/agents/templates/data_engineer.json +1 -1
- claude_mpm/agents/templates/documentation.json +1 -1
- claude_mpm/agents/templates/engineer.json +2 -2
- claude_mpm/agents/templates/gcp_ops_agent.json +14 -9
- claude_mpm/agents/templates/imagemagick.json +1 -1
- claude_mpm/agents/templates/memory_manager.json +1 -1
- claude_mpm/agents/templates/ops.json +1 -1
- claude_mpm/agents/templates/project_organizer.json +1 -1
- claude_mpm/agents/templates/qa.json +2 -2
- claude_mpm/agents/templates/refactoring_engineer.json +1 -1
- claude_mpm/agents/templates/research.json +3 -3
- claude_mpm/agents/templates/security.json +1 -1
- claude_mpm/agents/templates/test-non-mpm.json +20 -0
- claude_mpm/agents/templates/ticketing.json +1 -1
- claude_mpm/agents/templates/vercel_ops_agent.json +2 -2
- claude_mpm/agents/templates/version_control.json +1 -1
- claude_mpm/agents/templates/web_qa.json +3 -8
- claude_mpm/agents/templates/web_ui.json +1 -1
- claude_mpm/cli/commands/agents.py +3 -0
- claude_mpm/cli/commands/dashboard.py +3 -3
- claude_mpm/cli/commands/monitor.py +227 -64
- claude_mpm/core/config.py +25 -0
- claude_mpm/core/unified_agent_registry.py +2 -2
- claude_mpm/dashboard/static/css/code-tree.css +220 -1
- claude_mpm/dashboard/static/css/dashboard.css +286 -0
- claude_mpm/dashboard/static/dist/components/code-tree.js +1 -1
- claude_mpm/dashboard/static/js/components/code-simple.js +507 -15
- claude_mpm/dashboard/static/js/components/code-tree.js +2044 -124
- claude_mpm/dashboard/static/js/socket-client.js +5 -2
- claude_mpm/dashboard/templates/code_simple.html +79 -0
- claude_mpm/dashboard/templates/index.html +42 -41
- claude_mpm/services/agents/deployment/agent_deployment.py +4 -1
- claude_mpm/services/agents/deployment/agent_discovery_service.py +101 -2
- claude_mpm/services/agents/deployment/agent_format_converter.py +53 -9
- claude_mpm/services/agents/deployment/agent_template_builder.py +355 -25
- claude_mpm/services/agents/deployment/agent_validator.py +11 -6
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +83 -15
- claude_mpm/services/agents/deployment/validation/template_validator.py +51 -40
- claude_mpm/services/cli/agent_listing_service.py +2 -2
- claude_mpm/services/dashboard/stable_server.py +389 -0
- claude_mpm/services/socketio/client_proxy.py +16 -0
- claude_mpm/services/socketio/dashboard_server.py +360 -0
- claude_mpm/services/socketio/handlers/code_analysis.py +27 -5
- claude_mpm/services/socketio/monitor_client.py +366 -0
- claude_mpm/services/socketio/monitor_server.py +505 -0
- claude_mpm/tools/code_tree_analyzer.py +95 -17
- {claude_mpm-4.2.1.dist-info → claude_mpm-4.2.3.dist-info}/METADATA +1 -1
- {claude_mpm-4.2.1.dist-info → claude_mpm-4.2.3.dist-info}/RECORD +57 -52
- {claude_mpm-4.2.1.dist-info → claude_mpm-4.2.3.dist-info}/WHEEL +0 -0
- {claude_mpm-4.2.1.dist-info → claude_mpm-4.2.3.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.2.1.dist-info → claude_mpm-4.2.3.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.2.1.dist-info → claude_mpm-4.2.3.dist-info}/top_level.txt +0 -0
|
@@ -20,6 +20,15 @@ function goUp() {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
function analyzeFileFromPath(filePath) {
|
|
24
|
+
console.log('[analyzeFileFromPath] Called with path:', filePath);
|
|
25
|
+
if (window.simpleCodeView) {
|
|
26
|
+
window.simpleCodeView.analyzeFileFromPath(filePath);
|
|
27
|
+
} else {
|
|
28
|
+
console.error('[analyzeFileFromPath] simpleCodeView not initialized');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
23
32
|
class SimpleCodeView {
|
|
24
33
|
constructor() {
|
|
25
34
|
console.log('[SimpleCodeView] Constructor called');
|
|
@@ -27,6 +36,17 @@ class SimpleCodeView {
|
|
|
27
36
|
this.container = null;
|
|
28
37
|
this.apiBase = window.location.origin;
|
|
29
38
|
console.log('[SimpleCodeView] API base:', this.apiBase);
|
|
39
|
+
|
|
40
|
+
// Tree view properties
|
|
41
|
+
this.currentView = 'directory';
|
|
42
|
+
this.socket = null;
|
|
43
|
+
this.svg = null;
|
|
44
|
+
this.treeGroup = null;
|
|
45
|
+
this.treeLayout = null;
|
|
46
|
+
this.treeData = null;
|
|
47
|
+
this.width = 800;
|
|
48
|
+
this.height = 600;
|
|
49
|
+
this.margin = {top: 20, right: 20, bottom: 20, left: 120};
|
|
30
50
|
}
|
|
31
51
|
|
|
32
52
|
init(container) {
|
|
@@ -53,7 +73,18 @@ class SimpleCodeView {
|
|
|
53
73
|
|
|
54
74
|
const html = `
|
|
55
75
|
<div class="simple-code-view" style="padding: 20px;">
|
|
56
|
-
<h2>Simple
|
|
76
|
+
<h2>Simple Code Browser</h2>
|
|
77
|
+
|
|
78
|
+
<div class="view-toggle" style="margin: 10px 0; padding: 10px; background: #f0f0f0; border-radius: 4px;">
|
|
79
|
+
<button id="dir-view-btn" onclick="window.simpleCodeView.setView('directory')" class="active"
|
|
80
|
+
style="margin-right: 10px; padding: 8px 16px; border: 1px solid #ccc; background: #007cba; color: white; border-radius: 4px; cursor: pointer;">
|
|
81
|
+
📁 Directory View
|
|
82
|
+
</button>
|
|
83
|
+
<button id="tree-view-btn" onclick="window.simpleCodeView.setView('tree')"
|
|
84
|
+
style="padding: 8px 16px; border: 1px solid #ccc; background: #f9f9f9; color: #333; border-radius: 4px; cursor: pointer;">
|
|
85
|
+
🌳 Tree View
|
|
86
|
+
</button>
|
|
87
|
+
</div>
|
|
57
88
|
|
|
58
89
|
<div id="status-bar" style="padding: 10px; background: #e0e0e0; border-radius: 4px; margin-bottom: 10px;">
|
|
59
90
|
Status: Initializing...
|
|
@@ -73,6 +104,20 @@ class SimpleCodeView {
|
|
|
73
104
|
<div style="color: #666;">Waiting to load directory...</div>
|
|
74
105
|
</div>
|
|
75
106
|
|
|
107
|
+
<div id="tree-view-container" style="display: none;">
|
|
108
|
+
<div class="file-selector" style="margin: 10px 0; padding: 10px; background: #f9f9f9; border-radius: 4px;">
|
|
109
|
+
<input type="text" id="file-path-input" placeholder="Enter file path to analyze (e.g., ./src/claude_mpm/core/framework_loader.py)"
|
|
110
|
+
style="width: 70%; padding: 8px; margin-right: 10px; border: 1px solid #ccc; border-radius: 4px;">
|
|
111
|
+
<button onclick="window.simpleCodeView.analyzeFile()"
|
|
112
|
+
style="padding: 8px 16px; border: 1px solid #ccc; background: #28a745; color: white; border-radius: 4px; cursor: pointer;">
|
|
113
|
+
Analyze File
|
|
114
|
+
</button>
|
|
115
|
+
</div>
|
|
116
|
+
<div id="tree-visualization" style="border: 1px solid #ccc; min-height: 500px; background: white; overflow: auto; position: relative;">
|
|
117
|
+
<div style="padding: 20px; text-align: center; color: #666;">Enter a file path above and click "Analyze File" to view AST tree</div>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
76
121
|
<div id="debug-info" style="margin-top: 10px; padding: 10px; background: #f9f9f9; font-family: monospace; font-size: 12px;">
|
|
77
122
|
<strong>Debug Info:</strong><br>
|
|
78
123
|
API Base: ${this.apiBase}<br>
|
|
@@ -225,27 +270,31 @@ class SimpleCodeView {
|
|
|
225
270
|
});
|
|
226
271
|
|
|
227
272
|
for (const item of sorted) {
|
|
228
|
-
let icon = item.is_directory ? '📁' : '📄';
|
|
229
|
-
let nameStyle = 'color: #666;';
|
|
230
|
-
|
|
231
|
-
// Special styling for code files
|
|
232
|
-
if (!item.is_directory && item.is_code_file) {
|
|
233
|
-
icon = '💻'; // Code file icon
|
|
234
|
-
nameStyle = 'color: #2e7d32; font-weight: 500;'; // Green color for code files
|
|
235
|
-
}
|
|
236
|
-
|
|
237
273
|
if (item.is_directory) {
|
|
238
274
|
// Make directories clickable
|
|
239
275
|
html += `<li style="padding: 5px 0;">
|
|
240
|
-
|
|
276
|
+
📁 <a href="#" onclick="loadDir('${item.path.replace(/'/g, "\\'")}'); return false;" style="color: blue; text-decoration: none; cursor: pointer;">
|
|
241
277
|
${item.name}/
|
|
242
278
|
</a>
|
|
243
279
|
</li>`;
|
|
244
280
|
} else {
|
|
245
|
-
//
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
281
|
+
// Check if it's a code file and make it clickable
|
|
282
|
+
const isCodeFile = this.isCodeFile(item.name);
|
|
283
|
+
const fileIcon = this.getFileIcon(item.name);
|
|
284
|
+
|
|
285
|
+
if (isCodeFile) {
|
|
286
|
+
// Code files - clickable to show AST
|
|
287
|
+
html += `<li style="padding: 5px 0;">
|
|
288
|
+
${fileIcon} <a href="#" onclick="analyzeFileFromPath('${item.path.replace(/'/g, "\\'")}'); return false;" style="color: #0066cc; text-decoration: none; cursor: pointer; font-weight: 500;" title="Click to view AST">
|
|
289
|
+
${item.name}
|
|
290
|
+
</a>
|
|
291
|
+
</li>`;
|
|
292
|
+
} else {
|
|
293
|
+
// Non-code files - not clickable
|
|
294
|
+
html += `<li style="padding: 5px 0;">
|
|
295
|
+
📄 <span style="color: #666;">${item.name}</span>
|
|
296
|
+
</li>`;
|
|
297
|
+
}
|
|
249
298
|
}
|
|
250
299
|
}
|
|
251
300
|
|
|
@@ -289,6 +338,449 @@ class SimpleCodeView {
|
|
|
289
338
|
console.log('[SimpleCodeView.goUp] Going up to:', parent);
|
|
290
339
|
this.loadDirectory(parent);
|
|
291
340
|
}
|
|
341
|
+
|
|
342
|
+
// Tree view methods
|
|
343
|
+
setView(view) {
|
|
344
|
+
console.log('[SimpleCodeView.setView] Switching to view:', view);
|
|
345
|
+
this.currentView = view;
|
|
346
|
+
|
|
347
|
+
const dirContents = document.getElementById('directory-contents');
|
|
348
|
+
const treeContainer = document.getElementById('tree-view-container');
|
|
349
|
+
const dirBtn = document.getElementById('dir-view-btn');
|
|
350
|
+
const treeBtn = document.getElementById('tree-view-btn');
|
|
351
|
+
|
|
352
|
+
if (view === 'tree') {
|
|
353
|
+
dirContents.style.display = 'none';
|
|
354
|
+
treeContainer.style.display = 'block';
|
|
355
|
+
|
|
356
|
+
// Update button styles
|
|
357
|
+
dirBtn.style.background = '#f9f9f9';
|
|
358
|
+
dirBtn.style.color = '#333';
|
|
359
|
+
dirBtn.classList.remove('active');
|
|
360
|
+
|
|
361
|
+
treeBtn.style.background = '#007cba';
|
|
362
|
+
treeBtn.style.color = 'white';
|
|
363
|
+
treeBtn.classList.add('active');
|
|
364
|
+
|
|
365
|
+
this.initializeTreeView();
|
|
366
|
+
} else {
|
|
367
|
+
dirContents.style.display = 'block';
|
|
368
|
+
treeContainer.style.display = 'none';
|
|
369
|
+
|
|
370
|
+
// Update button styles
|
|
371
|
+
treeBtn.style.background = '#f9f9f9';
|
|
372
|
+
treeBtn.style.color = '#333';
|
|
373
|
+
treeBtn.classList.remove('active');
|
|
374
|
+
|
|
375
|
+
dirBtn.style.background = '#007cba';
|
|
376
|
+
dirBtn.style.color = 'white';
|
|
377
|
+
dirBtn.classList.add('active');
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
initializeTreeView() {
|
|
382
|
+
console.log('[SimpleCodeView.initializeTreeView] Initializing tree view');
|
|
383
|
+
|
|
384
|
+
if (!window.d3) {
|
|
385
|
+
this.updateStatus('D3.js not loaded - cannot initialize tree view', 'red');
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
this.initializeSocket();
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
initializeSocket() {
|
|
393
|
+
console.log('[SimpleCodeView.initializeSocket] Initializing Socket.IO connection');
|
|
394
|
+
|
|
395
|
+
if (!window.io) {
|
|
396
|
+
this.updateStatus('Socket.IO not loaded - using fallback mode', 'orange');
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
try {
|
|
401
|
+
this.socket = io('/');
|
|
402
|
+
|
|
403
|
+
this.socket.on('connect', () => {
|
|
404
|
+
console.log('[SimpleCodeView] Socket connected');
|
|
405
|
+
this.updateStatus('Connected to analysis server', 'green');
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
this.socket.on('disconnect', () => {
|
|
409
|
+
console.log('[SimpleCodeView] Socket disconnected');
|
|
410
|
+
this.updateStatus('Disconnected from analysis server', 'orange');
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
this.socket.on('analysis_progress', (data) => {
|
|
414
|
+
console.log('[SimpleCodeView] Analysis progress:', data);
|
|
415
|
+
this.updateStatus(`Analysis: ${data.message}`, 'blue');
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
this.socket.on('analysis_complete', (data) => {
|
|
419
|
+
console.log('[SimpleCodeView] Analysis complete:', data);
|
|
420
|
+
this.updateStatus('Analysis complete - rendering tree', 'green');
|
|
421
|
+
this.renderTree(data);
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
this.socket.on('analysis_error', (error) => {
|
|
425
|
+
console.error('[SimpleCodeView] Analysis error:', error);
|
|
426
|
+
this.showError(`Analysis failed: ${error.message || error}`);
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
} catch (error) {
|
|
430
|
+
console.error('[SimpleCodeView] Failed to initialize socket:', error);
|
|
431
|
+
this.updateStatus('Socket connection failed - using fallback mode', 'orange');
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
async analyzeFile() {
|
|
436
|
+
console.log('[SimpleCodeView.analyzeFile] Starting file analysis');
|
|
437
|
+
|
|
438
|
+
const fileInput = document.getElementById('file-path-input');
|
|
439
|
+
const filePath = fileInput.value.trim();
|
|
440
|
+
|
|
441
|
+
if (!filePath) {
|
|
442
|
+
this.showError('Please enter a file path');
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
this.hideError();
|
|
447
|
+
this.updateStatus(`Analyzing file: ${filePath}`, 'blue');
|
|
448
|
+
|
|
449
|
+
// Clear previous tree
|
|
450
|
+
const treeViz = document.getElementById('tree-visualization');
|
|
451
|
+
if (treeViz) {
|
|
452
|
+
treeViz.innerHTML = '<div style="padding: 20px; text-align: center; color: #666;">Analyzing file...</div>';
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
try {
|
|
456
|
+
if (this.socket && this.socket.connected) {
|
|
457
|
+
// Use Socket.IO for real-time analysis
|
|
458
|
+
this.socket.emit('analyze_file', {
|
|
459
|
+
path: filePath,
|
|
460
|
+
working_directory: this.currentPath
|
|
461
|
+
});
|
|
462
|
+
} else {
|
|
463
|
+
// Fallback to HTTP API (we'll create a simple endpoint)
|
|
464
|
+
await this.analyzeFileHTTP(filePath);
|
|
465
|
+
}
|
|
466
|
+
} catch (error) {
|
|
467
|
+
console.error('[SimpleCodeView.analyzeFile] Error:', error);
|
|
468
|
+
this.showError(`Failed to analyze file: ${error.message}`);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
async analyzeFileHTTP(filePath) {
|
|
473
|
+
console.log('[SimpleCodeView.analyzeFileHTTP] Using HTTP fallback for:', filePath);
|
|
474
|
+
|
|
475
|
+
try {
|
|
476
|
+
// Create a simple mock analysis for demonstration
|
|
477
|
+
// In a real implementation, this would call a proper analysis endpoint
|
|
478
|
+
setTimeout(() => {
|
|
479
|
+
const mockData = this.createMockTreeData(filePath);
|
|
480
|
+
this.renderTree(mockData);
|
|
481
|
+
}, 1000);
|
|
482
|
+
|
|
483
|
+
} catch (error) {
|
|
484
|
+
throw new Error(`HTTP analysis failed: ${error.message}`);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
createMockTreeData(filePath) {
|
|
489
|
+
// Create mock AST data for demonstration
|
|
490
|
+
const fileName = filePath.split('/').pop() || 'file';
|
|
491
|
+
const ext = fileName.split('.').pop()?.toLowerCase();
|
|
492
|
+
|
|
493
|
+
let mockData = {
|
|
494
|
+
name: fileName,
|
|
495
|
+
type: 'module',
|
|
496
|
+
children: []
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
if (ext === 'py') {
|
|
500
|
+
mockData.children = [
|
|
501
|
+
{
|
|
502
|
+
name: 'imports',
|
|
503
|
+
type: 'imports',
|
|
504
|
+
children: [
|
|
505
|
+
{ name: 'import os', type: 'import' },
|
|
506
|
+
{ name: 'from pathlib import Path', type: 'import' }
|
|
507
|
+
]
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
name: 'MyClass',
|
|
511
|
+
type: 'class',
|
|
512
|
+
children: [
|
|
513
|
+
{ name: '__init__', type: 'method' },
|
|
514
|
+
{ name: 'process_data', type: 'method' },
|
|
515
|
+
{ name: 'save_results', type: 'method' }
|
|
516
|
+
]
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
name: 'helper_function',
|
|
520
|
+
type: 'function',
|
|
521
|
+
children: []
|
|
522
|
+
}
|
|
523
|
+
];
|
|
524
|
+
} else if (ext === 'js' || ext === 'ts') {
|
|
525
|
+
mockData.children = [
|
|
526
|
+
{
|
|
527
|
+
name: 'imports',
|
|
528
|
+
type: 'imports',
|
|
529
|
+
children: [
|
|
530
|
+
{ name: "import React from 'react'", type: 'import' },
|
|
531
|
+
{ name: "import { useState } from 'react'", type: 'import' }
|
|
532
|
+
]
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
name: 'MyComponent',
|
|
536
|
+
type: 'function',
|
|
537
|
+
children: [
|
|
538
|
+
{ name: 'useState', type: 'hook' },
|
|
539
|
+
{ name: 'useEffect', type: 'hook' },
|
|
540
|
+
{ name: 'handleClick', type: 'function' }
|
|
541
|
+
]
|
|
542
|
+
}
|
|
543
|
+
];
|
|
544
|
+
} else {
|
|
545
|
+
mockData.children = [
|
|
546
|
+
{ name: 'Content Section 1', type: 'section' },
|
|
547
|
+
{ name: 'Content Section 2', type: 'section' },
|
|
548
|
+
{ name: 'Content Section 3', type: 'section' }
|
|
549
|
+
];
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
return mockData;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
renderTree(data) {
|
|
556
|
+
console.log('[SimpleCodeView.renderTree] Rendering tree with data:', data);
|
|
557
|
+
|
|
558
|
+
if (!data || !window.d3) {
|
|
559
|
+
this.showError('Cannot render tree: missing data or D3.js');
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
this.treeData = data;
|
|
564
|
+
|
|
565
|
+
// Clear previous visualization
|
|
566
|
+
const container = document.getElementById('tree-visualization');
|
|
567
|
+
if (!container) {
|
|
568
|
+
this.showError('Tree visualization container not found');
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
container.innerHTML = '';
|
|
573
|
+
|
|
574
|
+
// Create SVG
|
|
575
|
+
const margin = this.margin;
|
|
576
|
+
const width = this.width - margin.left - margin.right;
|
|
577
|
+
const height = this.height - margin.top - margin.bottom;
|
|
578
|
+
|
|
579
|
+
this.svg = d3.select('#tree-visualization')
|
|
580
|
+
.append('svg')
|
|
581
|
+
.attr('width', this.width)
|
|
582
|
+
.attr('height', this.height);
|
|
583
|
+
|
|
584
|
+
// Add zoom behavior
|
|
585
|
+
const zoom = d3.zoom()
|
|
586
|
+
.scaleExtent([0.1, 4])
|
|
587
|
+
.on('zoom', (event) => {
|
|
588
|
+
this.treeGroup.attr('transform', event.transform);
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
this.svg.call(zoom);
|
|
592
|
+
|
|
593
|
+
// Create main group
|
|
594
|
+
this.treeGroup = this.svg.append('g')
|
|
595
|
+
.attr('transform', `translate(${margin.left},${margin.top})`);
|
|
596
|
+
|
|
597
|
+
// Create tree layout
|
|
598
|
+
this.treeLayout = d3.tree()
|
|
599
|
+
.size([height, width]);
|
|
600
|
+
|
|
601
|
+
// Convert data to hierarchy
|
|
602
|
+
const hierarchy = d3.hierarchy(data);
|
|
603
|
+
|
|
604
|
+
// Generate tree layout
|
|
605
|
+
const treeData = this.treeLayout(hierarchy);
|
|
606
|
+
|
|
607
|
+
// Add links
|
|
608
|
+
const links = this.treeGroup.selectAll('.link')
|
|
609
|
+
.data(treeData.links())
|
|
610
|
+
.enter()
|
|
611
|
+
.append('path')
|
|
612
|
+
.attr('class', 'link')
|
|
613
|
+
.attr('d', d3.linkHorizontal()
|
|
614
|
+
.x(d => d.y)
|
|
615
|
+
.y(d => d.x)
|
|
616
|
+
)
|
|
617
|
+
.style('fill', 'none')
|
|
618
|
+
.style('stroke', '#ccc')
|
|
619
|
+
.style('stroke-width', '2px');
|
|
620
|
+
|
|
621
|
+
// Add nodes
|
|
622
|
+
const nodes = this.treeGroup.selectAll('.node')
|
|
623
|
+
.data(treeData.descendants())
|
|
624
|
+
.enter()
|
|
625
|
+
.append('g')
|
|
626
|
+
.attr('class', 'tree-node')
|
|
627
|
+
.attr('transform', d => `translate(${d.y},${d.x})`);
|
|
628
|
+
|
|
629
|
+
// Add circles for nodes
|
|
630
|
+
nodes.append('circle')
|
|
631
|
+
.attr('r', 6)
|
|
632
|
+
.style('fill', d => this.getNodeColor(d.data.type))
|
|
633
|
+
.style('stroke', '#333')
|
|
634
|
+
.style('stroke-width', '2px');
|
|
635
|
+
|
|
636
|
+
// Add labels
|
|
637
|
+
nodes.append('text')
|
|
638
|
+
.attr('dy', '.35em')
|
|
639
|
+
.attr('x', d => d.children ? -13 : 13)
|
|
640
|
+
.style('text-anchor', d => d.children ? 'end' : 'start')
|
|
641
|
+
.style('font-size', '12px')
|
|
642
|
+
.style('font-family', 'Arial, sans-serif')
|
|
643
|
+
.text(d => d.data.name);
|
|
644
|
+
|
|
645
|
+
// Add tooltips
|
|
646
|
+
nodes.append('title')
|
|
647
|
+
.text(d => `${d.data.type}: ${d.data.name}`);
|
|
648
|
+
|
|
649
|
+
// Add legend
|
|
650
|
+
this.addLegend(container);
|
|
651
|
+
|
|
652
|
+
this.updateStatus('Tree visualization rendered successfully', 'green');
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
getNodeColor(type) {
|
|
656
|
+
const colors = {
|
|
657
|
+
'module': '#1f77b4',
|
|
658
|
+
'class': '#ff7f0e',
|
|
659
|
+
'function': '#2ca02c',
|
|
660
|
+
'method': '#d62728',
|
|
661
|
+
'import': '#9467bd',
|
|
662
|
+
'imports': '#8c564b',
|
|
663
|
+
'section': '#e377c2',
|
|
664
|
+
'hook': '#7f7f7f'
|
|
665
|
+
};
|
|
666
|
+
return colors[type] || '#bcbd22';
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// Check if file is a code file
|
|
670
|
+
isCodeFile(filename) {
|
|
671
|
+
const codeExtensions = [
|
|
672
|
+
'.py', '.js', '.jsx', '.ts', '.tsx', '.java', '.cpp', '.c', '.h',
|
|
673
|
+
'.cs', '.go', '.rs', '.rb', '.php', '.swift', '.kt', '.scala',
|
|
674
|
+
'.r', '.m', '.mm', '.sh', '.bash', '.zsh', '.sql', '.html',
|
|
675
|
+
'.css', '.scss', '.sass', '.less', '.xml', '.json', '.yaml', '.yml',
|
|
676
|
+
'.md', '.rst', '.txt', '.log', '.conf', '.ini', '.toml'
|
|
677
|
+
];
|
|
678
|
+
const ext = filename.toLowerCase().substring(filename.lastIndexOf('.'));
|
|
679
|
+
return codeExtensions.includes(ext);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// Get appropriate icon for file type
|
|
683
|
+
getFileIcon(filename) {
|
|
684
|
+
const ext = filename.toLowerCase().substring(filename.lastIndexOf('.'));
|
|
685
|
+
const iconMap = {
|
|
686
|
+
'.py': '🐍',
|
|
687
|
+
'.js': '📜',
|
|
688
|
+
'.jsx': '⚛️',
|
|
689
|
+
'.ts': '📘',
|
|
690
|
+
'.tsx': '⚛️',
|
|
691
|
+
'.json': '📋',
|
|
692
|
+
'.html': '🌐',
|
|
693
|
+
'.css': '🎨',
|
|
694
|
+
'.md': '📝',
|
|
695
|
+
'.yml': '⚙️',
|
|
696
|
+
'.yaml': '⚙️',
|
|
697
|
+
'.sh': '🔧',
|
|
698
|
+
'.go': '🐹',
|
|
699
|
+
'.rs': '🦀',
|
|
700
|
+
'.java': '☕',
|
|
701
|
+
'.rb': '💎',
|
|
702
|
+
'.php': '🐘',
|
|
703
|
+
'.cpp': '⚙️',
|
|
704
|
+
'.c': '⚙️',
|
|
705
|
+
'.h': '📄',
|
|
706
|
+
'.cs': '💜',
|
|
707
|
+
'.swift': '🦉',
|
|
708
|
+
'.kt': '🚀',
|
|
709
|
+
'.scala': '📈',
|
|
710
|
+
'.r': '📊',
|
|
711
|
+
'.sql': '🗃️',
|
|
712
|
+
'.scss': '🎨',
|
|
713
|
+
'.sass': '🎨',
|
|
714
|
+
'.less': '🎨',
|
|
715
|
+
'.xml': '📑',
|
|
716
|
+
'.bash': '🔧',
|
|
717
|
+
'.zsh': '🔧',
|
|
718
|
+
'.md': '📝',
|
|
719
|
+
'.rst': '📝',
|
|
720
|
+
'.txt': '📄',
|
|
721
|
+
'.log': '📋',
|
|
722
|
+
'.conf': '⚙️',
|
|
723
|
+
'.ini': '⚙️',
|
|
724
|
+
'.toml': '⚙️'
|
|
725
|
+
};
|
|
726
|
+
return iconMap[ext] || '💻';
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// New method to analyze file from directory click
|
|
730
|
+
analyzeFileFromPath(filePath) {
|
|
731
|
+
console.log('[SimpleCodeView.analyzeFileFromPath] Analyzing file:', filePath);
|
|
732
|
+
|
|
733
|
+
// Switch to tree view
|
|
734
|
+
this.setView('tree');
|
|
735
|
+
|
|
736
|
+
// Set the file path in the input
|
|
737
|
+
const fileInput = document.getElementById('file-path-input');
|
|
738
|
+
if (fileInput) {
|
|
739
|
+
fileInput.value = filePath;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// Trigger analysis
|
|
743
|
+
this.analyzeFile();
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
addLegend(container) {
|
|
747
|
+
// Remove existing legend
|
|
748
|
+
const existingLegend = container.querySelector('.tree-legend');
|
|
749
|
+
if (existingLegend) {
|
|
750
|
+
existingLegend.remove();
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
const legend = document.createElement('div');
|
|
754
|
+
legend.className = 'tree-legend';
|
|
755
|
+
|
|
756
|
+
const legendTypes = [
|
|
757
|
+
{ type: 'module', label: 'Module/File' },
|
|
758
|
+
{ type: 'class', label: 'Class' },
|
|
759
|
+
{ type: 'function', label: 'Function' },
|
|
760
|
+
{ type: 'method', label: 'Method' },
|
|
761
|
+
{ type: 'imports', label: 'Imports' },
|
|
762
|
+
{ type: 'import', label: 'Import' },
|
|
763
|
+
{ type: 'section', label: 'Section' },
|
|
764
|
+
{ type: 'hook', label: 'Hook/Other' }
|
|
765
|
+
];
|
|
766
|
+
|
|
767
|
+
legend.innerHTML = `
|
|
768
|
+
<strong>Legend</strong><br>
|
|
769
|
+
${legendTypes.map(item => `
|
|
770
|
+
<div class="tree-legend-item">
|
|
771
|
+
<div class="tree-legend-color" style="background-color: ${this.getNodeColor(item.type)};"></div>
|
|
772
|
+
${item.label}
|
|
773
|
+
</div>
|
|
774
|
+
`).join('')}
|
|
775
|
+
<hr style="margin: 8px 0;">
|
|
776
|
+
<div style="font-size: 11px; color: #666;">
|
|
777
|
+
Zoom: Mouse wheel<br>
|
|
778
|
+
Pan: Click and drag
|
|
779
|
+
</div>
|
|
780
|
+
`;
|
|
781
|
+
|
|
782
|
+
container.appendChild(legend);
|
|
783
|
+
}
|
|
292
784
|
}
|
|
293
785
|
|
|
294
786
|
// Create global instance
|