claude-mpm 4.2.44__py3-none-any.whl → 4.2.51__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.
Files changed (148) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_PM.md +43 -1
  3. claude_mpm/agents/INSTRUCTIONS.md +75 -1
  4. claude_mpm/agents/WORKFLOW.md +46 -1
  5. claude_mpm/agents/frontmatter_validator.py +20 -12
  6. claude_mpm/agents/templates/nextjs_engineer.json +277 -0
  7. claude_mpm/agents/templates/python_engineer.json +289 -0
  8. claude_mpm/agents/templates/react_engineer.json +11 -3
  9. claude_mpm/agents/templates/security.json +50 -9
  10. claude_mpm/cli/commands/agents.py +2 -2
  11. claude_mpm/cli/commands/uninstall.py +1 -2
  12. claude_mpm/cli/interactive/agent_wizard.py +3 -3
  13. claude_mpm/cli/parsers/agent_manager_parser.py +3 -3
  14. claude_mpm/cli/parsers/agents_parser.py +1 -1
  15. claude_mpm/constants.py +1 -1
  16. claude_mpm/core/error_handler.py +2 -4
  17. claude_mpm/core/file_utils.py +4 -12
  18. claude_mpm/core/log_manager.py +8 -5
  19. claude_mpm/core/logger.py +1 -1
  20. claude_mpm/core/logging_utils.py +6 -6
  21. claude_mpm/core/unified_agent_registry.py +18 -4
  22. claude_mpm/dashboard/react/components/DataInspector/DataInspector.module.css +188 -0
  23. claude_mpm/dashboard/react/components/EventViewer/EventViewer.module.css +156 -0
  24. claude_mpm/dashboard/react/components/shared/ConnectionStatus.module.css +38 -0
  25. claude_mpm/dashboard/react/components/shared/FilterBar.module.css +92 -0
  26. claude_mpm/dashboard/static/archive/activity_dashboard_fixed.html +248 -0
  27. claude_mpm/dashboard/static/archive/activity_dashboard_test.html +61 -0
  28. claude_mpm/dashboard/static/archive/test_activity_connection.html +179 -0
  29. claude_mpm/dashboard/static/archive/test_claude_tree_tab.html +68 -0
  30. claude_mpm/dashboard/static/archive/test_dashboard.html +409 -0
  31. claude_mpm/dashboard/static/archive/test_dashboard_fixed.html +519 -0
  32. claude_mpm/dashboard/static/archive/test_dashboard_verification.html +181 -0
  33. claude_mpm/dashboard/static/archive/test_file_data.html +315 -0
  34. claude_mpm/dashboard/static/archive/test_file_tree_empty_state.html +243 -0
  35. claude_mpm/dashboard/static/archive/test_file_tree_fix.html +234 -0
  36. claude_mpm/dashboard/static/archive/test_file_tree_rename.html +117 -0
  37. claude_mpm/dashboard/static/archive/test_file_tree_tab.html +115 -0
  38. claude_mpm/dashboard/static/archive/test_file_viewer.html +224 -0
  39. claude_mpm/dashboard/static/archive/test_final_activity.html +220 -0
  40. claude_mpm/dashboard/static/archive/test_tab_fix.html +139 -0
  41. claude_mpm/dashboard/static/built/assets/events.DjpNxWNo.css +1 -0
  42. claude_mpm/dashboard/static/built/components/activity-tree.js +1 -1
  43. claude_mpm/dashboard/static/built/components/agent-hierarchy.js +777 -0
  44. claude_mpm/dashboard/static/built/components/agent-inference.js +1 -1
  45. claude_mpm/dashboard/static/built/components/build-tracker.js +333 -0
  46. claude_mpm/dashboard/static/built/components/code-simple.js +857 -0
  47. claude_mpm/dashboard/static/built/components/code-tree/tree-breadcrumb.js +353 -0
  48. claude_mpm/dashboard/static/built/components/code-tree/tree-constants.js +235 -0
  49. claude_mpm/dashboard/static/built/components/code-tree/tree-search.js +409 -0
  50. claude_mpm/dashboard/static/built/components/code-tree/tree-utils.js +435 -0
  51. claude_mpm/dashboard/static/built/components/code-viewer.js +2 -1076
  52. claude_mpm/dashboard/static/built/components/connection-debug.js +654 -0
  53. claude_mpm/dashboard/static/built/components/diff-viewer.js +891 -0
  54. claude_mpm/dashboard/static/built/components/event-processor.js +1 -1
  55. claude_mpm/dashboard/static/built/components/event-viewer.js +1 -1
  56. claude_mpm/dashboard/static/built/components/export-manager.js +1 -1
  57. claude_mpm/dashboard/static/built/components/file-change-tracker.js +443 -0
  58. claude_mpm/dashboard/static/built/components/file-change-viewer.js +690 -0
  59. claude_mpm/dashboard/static/built/components/file-tool-tracker.js +1 -1
  60. claude_mpm/dashboard/static/built/components/module-viewer.js +1 -1
  61. claude_mpm/dashboard/static/built/components/nav-bar.js +145 -0
  62. claude_mpm/dashboard/static/built/components/page-structure.js +429 -0
  63. claude_mpm/dashboard/static/built/components/session-manager.js +1 -1
  64. claude_mpm/dashboard/static/built/components/ui-state-manager.js +2 -465
  65. claude_mpm/dashboard/static/built/components/working-directory.js +1 -1
  66. claude_mpm/dashboard/static/built/connection-manager.js +536 -0
  67. claude_mpm/dashboard/static/built/dashboard.js +1 -1
  68. claude_mpm/dashboard/static/built/extension-error-handler.js +164 -0
  69. claude_mpm/dashboard/static/built/react/events.js +30 -0
  70. claude_mpm/dashboard/static/built/shared/dom-helpers.js +396 -0
  71. claude_mpm/dashboard/static/built/shared/event-bus.js +330 -0
  72. claude_mpm/dashboard/static/built/shared/event-filter-service.js +540 -0
  73. claude_mpm/dashboard/static/built/shared/logger.js +385 -0
  74. claude_mpm/dashboard/static/built/shared/page-structure.js +251 -0
  75. claude_mpm/dashboard/static/built/shared/tooltip-service.js +253 -0
  76. claude_mpm/dashboard/static/built/socket-client.js +1 -1
  77. claude_mpm/dashboard/static/built/tab-isolation-fix.js +185 -0
  78. claude_mpm/dashboard/static/css/dashboard.css +28 -5
  79. claude_mpm/dashboard/static/dist/assets/events.DjpNxWNo.css +1 -0
  80. claude_mpm/dashboard/static/dist/components/activity-tree.js +1 -1
  81. claude_mpm/dashboard/static/dist/components/agent-inference.js +1 -1
  82. claude_mpm/dashboard/static/dist/components/code-viewer.js +2 -0
  83. claude_mpm/dashboard/static/dist/components/event-processor.js +1 -1
  84. claude_mpm/dashboard/static/dist/components/event-viewer.js +1 -1
  85. claude_mpm/dashboard/static/dist/components/export-manager.js +1 -1
  86. claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +1 -1
  87. claude_mpm/dashboard/static/dist/components/module-viewer.js +1 -1
  88. claude_mpm/dashboard/static/dist/components/session-manager.js +1 -1
  89. claude_mpm/dashboard/static/dist/components/working-directory.js +1 -1
  90. claude_mpm/dashboard/static/dist/dashboard.js +1 -1
  91. claude_mpm/dashboard/static/dist/react/events.js +30 -0
  92. claude_mpm/dashboard/static/dist/socket-client.js +1 -1
  93. claude_mpm/dashboard/static/events.html +607 -0
  94. claude_mpm/dashboard/static/index.html +713 -0
  95. claude_mpm/dashboard/static/js/components/activity-tree.js +3 -17
  96. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +4 -1
  97. claude_mpm/dashboard/static/js/components/agent-inference.js +3 -0
  98. claude_mpm/dashboard/static/js/components/build-tracker.js +8 -0
  99. claude_mpm/dashboard/static/js/components/code-viewer.js +306 -66
  100. claude_mpm/dashboard/static/js/components/event-processor.js +3 -0
  101. claude_mpm/dashboard/static/js/components/event-viewer.js +39 -2
  102. claude_mpm/dashboard/static/js/components/export-manager.js +3 -0
  103. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +30 -10
  104. claude_mpm/dashboard/static/js/components/socket-manager.js +4 -0
  105. claude_mpm/dashboard/static/js/components/ui-state-manager.js +285 -85
  106. claude_mpm/dashboard/static/js/components/working-directory.js +3 -0
  107. claude_mpm/dashboard/static/js/dashboard.js +61 -33
  108. claude_mpm/dashboard/static/js/socket-client.js +12 -8
  109. claude_mpm/dashboard/static/js/stores/dashboard-store.js +562 -0
  110. claude_mpm/dashboard/static/js/tab-isolation-fix.js +185 -0
  111. claude_mpm/dashboard/static/legacy/activity.html +736 -0
  112. claude_mpm/dashboard/static/legacy/agents.html +786 -0
  113. claude_mpm/dashboard/static/legacy/files.html +747 -0
  114. claude_mpm/dashboard/static/legacy/tools.html +831 -0
  115. claude_mpm/dashboard/static/monitors-index.html +218 -0
  116. claude_mpm/dashboard/static/monitors.html +431 -0
  117. claude_mpm/dashboard/static/production/events.html +659 -0
  118. claude_mpm/dashboard/static/production/main.html +715 -0
  119. claude_mpm/dashboard/static/production/monitors.html +483 -0
  120. claude_mpm/dashboard/static/socket.io.min.js +7 -0
  121. claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +7 -0
  122. claude_mpm/dashboard/static/test-archive/dashboard.html +635 -0
  123. claude_mpm/dashboard/static/test-archive/debug-events.html +147 -0
  124. claude_mpm/dashboard/static/test-archive/test-navigation.html +256 -0
  125. claude_mpm/dashboard/static/test-archive/test-react-exports.html +180 -0
  126. claude_mpm/dashboard/templates/index.html +79 -9
  127. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +1 -1
  128. claude_mpm/services/agents/deployment/agent_discovery_service.py +3 -0
  129. claude_mpm/services/agents/deployment/agent_template_builder.py +25 -8
  130. claude_mpm/services/agents/deployment/agent_validator.py +3 -0
  131. claude_mpm/services/agents/deployment/validation/template_validator.py +13 -4
  132. claude_mpm/services/agents/local_template_manager.py +2 -6
  133. claude_mpm/services/monitor/daemon.py +1 -2
  134. claude_mpm/services/monitor/daemon_manager.py +2 -5
  135. claude_mpm/services/monitor/event_emitter.py +2 -2
  136. claude_mpm/services/monitor/handlers/code_analysis.py +4 -6
  137. claude_mpm/services/monitor/handlers/hooks.py +2 -4
  138. claude_mpm/services/monitor/server.py +27 -4
  139. claude_mpm/tools/code_tree_analyzer.py +2 -2
  140. {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/METADATA +1 -1
  141. {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/RECORD +146 -81
  142. claude_mpm/dashboard/static/test-browser-monitor.html +0 -470
  143. claude_mpm/dashboard/static/test-simple.html +0 -97
  144. /claude_mpm/dashboard/static/{test_debug.html → test-archive/test_debug.html} +0 -0
  145. {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/WHEEL +0 -0
  146. {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/entry_points.txt +0 -0
  147. {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/licenses/LICENSE +0 -0
  148. {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,435 @@
1
+ /**
2
+ * Tree Utility Functions
3
+ *
4
+ * Common utility functions extracted from code-tree.js
5
+ * Provides formatting, file type detection, and other helper functions.
6
+ *
7
+ * @module tree-utils
8
+ */
9
+
10
+ const treeUtils = {
11
+ /**
12
+ * Get complexity level from numeric complexity
13
+ * @param {number} complexity - Complexity value
14
+ * @returns {string} Complexity level (low/medium/high)
15
+ */
16
+ getComplexityLevel(complexity) {
17
+ if (complexity <= 5) return 'low';
18
+ if (complexity <= 10) return 'medium';
19
+ return 'high';
20
+ },
21
+
22
+ /**
23
+ * Format file size for display
24
+ * @param {number} bytes - Size in bytes
25
+ * @returns {string} Formatted size string
26
+ */
27
+ formatFileSize(bytes) {
28
+ if (bytes === 0) return '0 B';
29
+ const k = 1024;
30
+ const sizes = ['B', 'KB', 'MB', 'GB'];
31
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
32
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
33
+ },
34
+
35
+ /**
36
+ * Get file extension from path
37
+ * @param {string} filePath - File path
38
+ * @returns {string} File extension (lowercase)
39
+ */
40
+ getFileExtension(filePath) {
41
+ if (!filePath) return '';
42
+ const parts = filePath.split('.');
43
+ return parts.length > 1 ? parts.pop().toLowerCase() : '';
44
+ },
45
+
46
+ /**
47
+ * Get descriptive file type for user messages
48
+ * @param {string} fileName - File name
49
+ * @returns {string} Human-readable file type description
50
+ */
51
+ getFileTypeDescription(fileName) {
52
+ if (!fileName) return 'File';
53
+
54
+ const ext = this.getFileExtension(fileName);
55
+ const baseName = fileName.toLowerCase();
56
+
57
+ // Special cases
58
+ if (baseName.endsWith('__init__.py')) {
59
+ return 'Python package initialization';
60
+ }
61
+ if (baseName === 'makefile') {
62
+ return 'Build configuration';
63
+ }
64
+ if (baseName.includes('config') || baseName.includes('settings')) {
65
+ return 'Configuration file';
66
+ }
67
+ if (baseName.includes('test') || baseName.includes('spec')) {
68
+ return 'Test file';
69
+ }
70
+
71
+ // By extension
72
+ const typeMap = {
73
+ 'py': 'Python file',
74
+ 'js': 'JavaScript file',
75
+ 'ts': 'TypeScript file',
76
+ 'jsx': 'React component',
77
+ 'tsx': 'React TypeScript component',
78
+ 'html': 'HTML document',
79
+ 'css': 'Stylesheet',
80
+ 'scss': 'SCSS stylesheet',
81
+ 'sass': 'Sass stylesheet',
82
+ 'less': 'LESS stylesheet',
83
+ 'json': 'JSON data',
84
+ 'md': 'Markdown document',
85
+ 'txt': 'Text file',
86
+ 'yml': 'YAML configuration',
87
+ 'yaml': 'YAML configuration',
88
+ 'xml': 'XML document',
89
+ 'sql': 'SQL script',
90
+ 'sh': 'Shell script',
91
+ 'bash': 'Bash script',
92
+ 'toml': 'TOML configuration',
93
+ 'ini': 'INI configuration',
94
+ 'env': 'Environment variables',
95
+ 'dockerfile': 'Docker configuration',
96
+ 'makefile': 'Build configuration',
97
+ 'gitignore': 'Git ignore rules',
98
+ 'readme': 'Documentation'
99
+ };
100
+
101
+ return typeMap[ext] || typeMap[baseName] || 'File';
102
+ },
103
+
104
+ /**
105
+ * Get file icon based on file type
106
+ * @param {string} filePath - File path
107
+ * @returns {string} Unicode emoji icon
108
+ */
109
+ getFileIcon(filePath) {
110
+ if (!filePath) return '📄';
111
+
112
+ const ext = this.getFileExtension(filePath);
113
+ const fileName = filePath.toLowerCase().split('/').pop();
114
+
115
+ const iconMap = {
116
+ // Programming languages
117
+ 'py': '🐍',
118
+ 'js': '📜',
119
+ 'ts': '📘',
120
+ 'jsx': '⚛️',
121
+ 'tsx': '⚛️',
122
+ 'java': '☕',
123
+ 'c': '🔷',
124
+ 'cpp': '🔷',
125
+ 'cs': '🔷',
126
+ 'go': '🐹',
127
+ 'rs': '🦀',
128
+ 'rb': '💎',
129
+ 'php': '🐘',
130
+ 'swift': '🦉',
131
+ 'kt': '🎯',
132
+
133
+ // Web files
134
+ 'html': '🌐',
135
+ 'css': '🎨',
136
+ 'scss': '🎨',
137
+ 'sass': '🎨',
138
+ 'less': '🎨',
139
+
140
+ // Data files
141
+ 'json': '📋',
142
+ 'xml': '📰',
143
+ 'csv': '📊',
144
+ 'sql': '🗃️',
145
+
146
+ // Documentation
147
+ 'md': '📝',
148
+ 'txt': '📄',
149
+ 'pdf': '📑',
150
+ 'doc': '📃',
151
+ 'docx': '📃',
152
+
153
+ // Configuration
154
+ 'yml': '⚙️',
155
+ 'yaml': '⚙️',
156
+ 'toml': '⚙️',
157
+ 'ini': '⚙️',
158
+ 'env': '🔐',
159
+
160
+ // Scripts
161
+ 'sh': '🐚',
162
+ 'bash': '🐚',
163
+ 'bat': '🖥️',
164
+ 'ps1': '🖥️',
165
+
166
+ // Special files
167
+ 'dockerfile': '🐳',
168
+ 'docker-compose.yml': '🐳',
169
+ 'makefile': '🔨',
170
+ 'package.json': '📦',
171
+ 'requirements.txt': '📦',
172
+ 'gitignore': '🚫',
173
+ '.gitignore': '🚫',
174
+ 'readme': '📖',
175
+ 'readme.md': '📖',
176
+ 'license': '📜',
177
+ 'license.md': '📜'
178
+ };
179
+
180
+ // Check full filename first, then extension
181
+ return iconMap[fileName] || iconMap[ext] || '📄';
182
+ },
183
+
184
+ /**
185
+ * Count different types of AST elements
186
+ * @param {Array} elements - AST elements
187
+ * @returns {Object} Element counts
188
+ */
189
+ getElementCounts(elements) {
190
+ const counts = {
191
+ classes: 0,
192
+ functions: 0,
193
+ methods: 0,
194
+ total: elements.length
195
+ };
196
+
197
+ elements.forEach(elem => {
198
+ if (elem.type === 'class') {
199
+ counts.classes++;
200
+ if (elem.methods) {
201
+ counts.methods += elem.methods.length;
202
+ }
203
+ } else if (elem.type === 'function') {
204
+ counts.functions++;
205
+ }
206
+ });
207
+
208
+ return counts;
209
+ },
210
+
211
+ /**
212
+ * Format element counts into a readable summary
213
+ * @param {Object} counts - Element counts
214
+ * @returns {string} Formatted summary
215
+ */
216
+ formatElementSummary(counts) {
217
+ const parts = [];
218
+
219
+ if (counts.classes > 0) {
220
+ parts.push(`${counts.classes} class${counts.classes !== 1 ? 'es' : ''}`);
221
+ }
222
+ if (counts.functions > 0) {
223
+ parts.push(`${counts.functions} function${counts.functions !== 1 ? 's' : ''}`);
224
+ }
225
+ if (counts.methods > 0) {
226
+ parts.push(`${counts.methods} method${counts.methods !== 1 ? 's' : ''}`);
227
+ }
228
+
229
+ if (parts.length === 0) {
230
+ return 'Structural elements for tree view';
231
+ } else if (parts.length === 1) {
232
+ return parts[0] + ' found';
233
+ } else if (parts.length === 2) {
234
+ return parts.join(' and ') + ' found';
235
+ } else {
236
+ return parts.slice(0, -1).join(', ') + ', and ' + parts[parts.length - 1] + ' found';
237
+ }
238
+ },
239
+
240
+ /**
241
+ * Get node type from data
242
+ * @param {Object} node - Node data
243
+ * @returns {string} Node type
244
+ */
245
+ getNodeType(node) {
246
+ if (!node) return 'unknown';
247
+ if (node.type) return node.type;
248
+ if (node.children && node.children.length > 0) return 'directory';
249
+ if (node.path) return 'file';
250
+ return 'unknown';
251
+ },
252
+
253
+ /**
254
+ * Check if node is a directory
255
+ * @param {Object} node - Node or node data
256
+ * @returns {boolean} True if directory
257
+ */
258
+ isNodeDirectory(node) {
259
+ if (!node) return false;
260
+
261
+ // Handle D3 node structure
262
+ if (node.data) {
263
+ node = node.data;
264
+ }
265
+
266
+ return node.type === 'directory' ||
267
+ node.type === 'folder' ||
268
+ (node.children && node.children.length > 0) ||
269
+ node.isDirectory === true;
270
+ },
271
+
272
+ /**
273
+ * Get node icon for tree visualization
274
+ * @param {string} type - Node type
275
+ * @returns {string} Unicode icon
276
+ */
277
+ getNodeIcon(type) {
278
+ const icons = {
279
+ 'module': '📦',
280
+ 'class': '🏗️',
281
+ 'function': '⚡',
282
+ 'method': '🔧',
283
+ 'property': '📌',
284
+ 'directory': '📁',
285
+ 'folder': '📁',
286
+ 'file': '📄',
287
+ 'python': '🐍',
288
+ 'javascript': '📜',
289
+ 'unknown': '❓'
290
+ };
291
+ return icons[type] || icons['unknown'];
292
+ },
293
+
294
+ /**
295
+ * Sort nodes for tree display
296
+ * @param {Array} nodes - Array of nodes
297
+ * @returns {Array} Sorted nodes
298
+ */
299
+ sortNodes(nodes) {
300
+ return nodes.sort((a, b) => {
301
+ // Directories first
302
+ const aIsDir = this.isNodeDirectory(a);
303
+ const bIsDir = this.isNodeDirectory(b);
304
+
305
+ if (aIsDir && !bIsDir) return -1;
306
+ if (!aIsDir && bIsDir) return 1;
307
+
308
+ // Then alphabetically
309
+ const aName = (a.name || a.data?.name || '').toLowerCase();
310
+ const bName = (b.name || b.data?.name || '').toLowerCase();
311
+
312
+ return aName.localeCompare(bName);
313
+ });
314
+ },
315
+
316
+ /**
317
+ * Filter nodes based on criteria
318
+ * @param {Array} nodes - Array of nodes
319
+ * @param {Object} criteria - Filter criteria
320
+ * @returns {Array} Filtered nodes
321
+ */
322
+ filterNodes(nodes, criteria = {}) {
323
+ return nodes.filter(node => {
324
+ // Language filter
325
+ if (criteria.language && node.language !== criteria.language) {
326
+ return false;
327
+ }
328
+
329
+ // Search term filter
330
+ if (criteria.searchTerm) {
331
+ const term = criteria.searchTerm.toLowerCase();
332
+ const name = (node.name || '').toLowerCase();
333
+ const path = (node.path || '').toLowerCase();
334
+
335
+ if (!name.includes(term) && !path.includes(term)) {
336
+ return false;
337
+ }
338
+ }
339
+
340
+ // Complexity filter
341
+ if (criteria.minComplexity && node.complexity < criteria.minComplexity) {
342
+ return false;
343
+ }
344
+ if (criteria.maxComplexity && node.complexity > criteria.maxComplexity) {
345
+ return false;
346
+ }
347
+
348
+ return true;
349
+ });
350
+ },
351
+
352
+ /**
353
+ * Calculate tree statistics
354
+ * @param {Object} node - Root node
355
+ * @returns {Object} Tree statistics
356
+ */
357
+ calculateTreeStats(node) {
358
+ const stats = {
359
+ files: 0,
360
+ directories: 0,
361
+ classes: 0,
362
+ functions: 0,
363
+ methods: 0,
364
+ lines: 0,
365
+ maxDepth: 0
366
+ };
367
+
368
+ const traverse = (n, depth = 0) => {
369
+ stats.maxDepth = Math.max(stats.maxDepth, depth);
370
+
371
+ if (this.isNodeDirectory(n)) {
372
+ stats.directories++;
373
+ } else {
374
+ stats.files++;
375
+ }
376
+
377
+ if (n.type === 'class') stats.classes++;
378
+ if (n.type === 'function') stats.functions++;
379
+ if (n.type === 'method') stats.methods++;
380
+ if (n.lines) stats.lines += n.lines;
381
+
382
+ if (n.children) {
383
+ n.children.forEach(child => traverse(child, depth + 1));
384
+ }
385
+ };
386
+
387
+ traverse(node);
388
+ return stats;
389
+ },
390
+
391
+ /**
392
+ * Get color based on complexity
393
+ * @param {number} complexity - Complexity value
394
+ * @returns {string} Color hex code
395
+ */
396
+ getComplexityColor(complexity) {
397
+ if (!complexity || complexity <= 5) {
398
+ return '#52c41a'; // Green - low complexity
399
+ } else if (complexity <= 10) {
400
+ return '#faad14'; // Orange - medium complexity
401
+ } else {
402
+ return '#f5222d'; // Red - high complexity
403
+ }
404
+ },
405
+
406
+ /**
407
+ * Format node path for display
408
+ * @param {Object} node - Node object
409
+ * @returns {string} Formatted path
410
+ */
411
+ formatNodePath(node) {
412
+ const parts = [];
413
+ let current = node;
414
+
415
+ while (current) {
416
+ if (current.data?.name) {
417
+ parts.unshift(current.data.name);
418
+ } else if (current.name) {
419
+ parts.unshift(current.name);
420
+ }
421
+ current = current.parent;
422
+ }
423
+
424
+ return parts.join(' / ');
425
+ }
426
+ };
427
+
428
+ // Support both module and global usage
429
+ if (typeof module !== 'undefined' && module.exports) {
430
+ module.exports = treeUtils;
431
+ } else if (typeof define === 'function' && define.amd) {
432
+ define([], () => treeUtils);
433
+ } else {
434
+ window.treeUtils = treeUtils;
435
+ }