claude-mpm 4.1.13__py3-none-any.whl → 4.1.14__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 CHANGED
@@ -1 +1 @@
1
- 4.1.13
1
+ 4.1.14
@@ -664,13 +664,13 @@ body .activity-tree-container .linear-tree .tree-node.tool.privileged-tool .tree
664
664
  color: #95A5A6;
665
665
  }
666
666
 
667
- /* Search Highlighting - Ensure this doesn't affect tools */
668
- .tree-node.search-match:not(.tool) {
667
+ /* Search Highlighting - Specific to activity tree only */
668
+ .activity-tree-container .tree-node.search-match:not(.tool) {
669
669
  background: #fff3cd !important;
670
670
  border-left-color: #ffc107 !important;
671
671
  }
672
672
 
673
- .tree-node.search-match:not(.tool) .tree-label {
673
+ .activity-tree-container .tree-node.search-match:not(.tool) .tree-label {
674
674
  background: #ffecb5;
675
675
  padding: 2px 4px;
676
676
  border-radius: 3px;
@@ -461,6 +461,13 @@
461
461
  position: relative;
462
462
  overflow: auto;
463
463
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
464
+ border-left: 1px solid #e2e8f0;
465
+ }
466
+
467
+ /* Visual hierarchy improvements */
468
+ .code-tree-container:focus-within {
469
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
470
+ border-left-color: #3b82f6;
464
471
  }
465
472
 
466
473
  /* Loading indicator */
@@ -710,6 +717,78 @@
710
717
  filter: brightness(1.1);
711
718
  }
712
719
 
720
+ /* Directory node styling - make expandable directories obvious */
721
+ .code-node.directory circle {
722
+ fill: #f8fafc;
723
+ stroke: #3b82f6;
724
+ stroke-width: 2px;
725
+ }
726
+
727
+ .code-node.directory:hover circle {
728
+ fill: #eef2ff;
729
+ stroke: #2563eb;
730
+ stroke-width: 3px;
731
+ filter: drop-shadow(0 2px 4px rgba(59, 130, 246, 0.3));
732
+ }
733
+
734
+ /* Expanded directory styling */
735
+ .code-node.directory.expanded circle {
736
+ fill: #dbeafe;
737
+ stroke: #1d4ed8;
738
+ }
739
+
740
+ /* File node styling */
741
+ .code-node.file circle {
742
+ fill: #f9fafb;
743
+ stroke: #6b7280;
744
+ stroke-width: 1.5px;
745
+ }
746
+
747
+ .code-node.file:hover circle {
748
+ fill: #f3f4f6;
749
+ stroke: #4b5563;
750
+ stroke-width: 2px;
751
+ }
752
+
753
+ /* Empty directory styling */
754
+ .code-node.directory.empty circle {
755
+ fill: #f9fafb;
756
+ stroke: #9ca3af;
757
+ stroke-dasharray: 3,3;
758
+ opacity: 0.7;
759
+ }
760
+
761
+ /* Directory expand/collapse icons */
762
+ .expand-icon {
763
+ font-family: monospace;
764
+ font-size: 12px;
765
+ font-weight: bold;
766
+ text-anchor: middle;
767
+ dominant-baseline: central;
768
+ fill: #374151;
769
+ pointer-events: none;
770
+ transition: all 0.2s ease;
771
+ }
772
+
773
+ .code-node.directory .expand-icon {
774
+ fill: #3b82f6;
775
+ }
776
+
777
+ .code-node.directory.expanded .expand-icon {
778
+ fill: #1d4ed8;
779
+ transform: rotate(90deg);
780
+ }
781
+
782
+ .code-node.directory.loading .expand-icon {
783
+ fill: #f59e0b;
784
+ animation: spin 1s linear infinite;
785
+ }
786
+
787
+ @keyframes spin {
788
+ from { transform: rotate(0deg); }
789
+ to { transform: rotate(360deg); }
790
+ }
791
+
713
792
  /* Visualization Controls */
714
793
  .viz-controls {
715
794
  position: absolute;
@@ -802,6 +881,31 @@
802
881
  fill: #ec4899;
803
882
  }
804
883
 
884
+ /* Search match highlighting */
885
+ .code-node.search-match circle {
886
+ stroke: #fbbf24 !important;
887
+ stroke-width: 3px;
888
+ fill: #fef3c7 !important;
889
+ filter: drop-shadow(0 0 8px rgba(251, 191, 36, 0.6));
890
+ animation: searchPulse 2s ease-in-out infinite;
891
+ }
892
+
893
+ .code-node.search-match text {
894
+ font-weight: bold;
895
+ fill: #92400e;
896
+ }
897
+
898
+ @keyframes searchPulse {
899
+ 0%, 100% {
900
+ stroke-width: 3px;
901
+ opacity: 1;
902
+ }
903
+ 50% {
904
+ stroke-width: 4px;
905
+ opacity: 0.8;
906
+ }
907
+ }
908
+
805
909
  /* Collapsed node indicator */
806
910
  .code-node.collapsed circle {
807
911
  fill: #e2e8f0 !important;
@@ -851,6 +955,31 @@
851
955
  fill: #fef3c7 !important;
852
956
  }
853
957
 
958
+ /* Enhanced loading states */
959
+ .code-node.loading circle {
960
+ stroke: #f59e0b !important;
961
+ fill: #fef3c7 !important;
962
+ animation: nodePulse 1.5s ease-in-out infinite;
963
+ }
964
+
965
+ .code-node.loading text {
966
+ fill: #92400e;
967
+ font-weight: 600;
968
+ }
969
+
970
+ /* Directory item count badge */
971
+ .item-count-badge {
972
+ font-size: 10px;
973
+ fill: #6b7280;
974
+ text-anchor: middle;
975
+ dominant-baseline: central;
976
+ font-weight: 500;
977
+ }
978
+
979
+ .code-node.directory:hover .item-count-badge {
980
+ fill: #374151;
981
+ }
982
+
854
983
  /* Tooltips */
855
984
  .code-tooltip {
856
985
  position: absolute;
@@ -864,11 +993,115 @@
864
993
  z-index: 1000;
865
994
  }
866
995
 
996
+ /* Tree control toolbar */
997
+ .tree-controls-toolbar {
998
+ position: absolute;
999
+ top: 15px;
1000
+ right: 15px;
1001
+ display: flex;
1002
+ gap: 8px;
1003
+ z-index: 100;
1004
+ background: rgba(255, 255, 255, 0.95);
1005
+ backdrop-filter: blur(4px);
1006
+ border: 1px solid #e5e7eb;
1007
+ border-radius: 8px;
1008
+ padding: 6px;
1009
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
1010
+ }
1011
+
1012
+ .tree-control-btn {
1013
+ padding: 6px 10px;
1014
+ font-size: 12px;
1015
+ font-weight: 500;
1016
+ border: 1px solid #d1d5db;
1017
+ background: white;
1018
+ color: #374151;
1019
+ border-radius: 4px;
1020
+ cursor: pointer;
1021
+ transition: all 0.2s ease;
1022
+ display: flex;
1023
+ align-items: center;
1024
+ gap: 4px;
1025
+ min-width: 32px;
1026
+ justify-content: center;
1027
+ }
1028
+
1029
+ .tree-control-btn:hover {
1030
+ background: #f3f4f6;
1031
+ border-color: #9ca3af;
1032
+ transform: translateY(-1px);
1033
+ }
1034
+
1035
+ .tree-control-btn:active {
1036
+ transform: translateY(0);
1037
+ }
1038
+
1039
+ .tree-control-btn.active {
1040
+ background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
1041
+ color: white;
1042
+ border-color: #2563eb;
1043
+ box-shadow: 0 2px 4px rgba(59, 130, 246, 0.3);
1044
+ }
1045
+
1046
+ .tree-control-btn:disabled {
1047
+ opacity: 0.5;
1048
+ cursor: not-allowed;
1049
+ transform: none;
1050
+ }
1051
+
1052
+ /* Breadcrumb navigation */
1053
+ .tree-breadcrumb {
1054
+ position: absolute;
1055
+ top: 15px;
1056
+ left: 15px;
1057
+ background: rgba(255, 255, 255, 0.95);
1058
+ backdrop-filter: blur(4px);
1059
+ border: 1px solid #e5e7eb;
1060
+ border-radius: 8px;
1061
+ padding: 6px 12px;
1062
+ font-size: 12px;
1063
+ color: #4b5563;
1064
+ font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
1065
+ max-width: 400px;
1066
+ z-index: 100;
1067
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
1068
+ }
1069
+
1070
+ .breadcrumb-path {
1071
+ display: flex;
1072
+ align-items: center;
1073
+ gap: 4px;
1074
+ font-weight: 500;
1075
+ }
1076
+
1077
+ .breadcrumb-separator {
1078
+ color: #9ca3af;
1079
+ margin: 0 2px;
1080
+ }
1081
+
1082
+ .breadcrumb-segment {
1083
+ color: #374151;
1084
+ cursor: pointer;
1085
+ padding: 2px 4px;
1086
+ border-radius: 3px;
1087
+ transition: background 0.2s ease;
1088
+ }
1089
+
1090
+ .breadcrumb-segment:hover {
1091
+ background: rgba(59, 130, 246, 0.1);
1092
+ color: #3b82f6;
1093
+ }
1094
+
1095
+ .breadcrumb-segment.current {
1096
+ color: #3b82f6;
1097
+ font-weight: 600;
1098
+ }
1099
+
867
1100
  /* Code tree notifications */
868
1101
  .code-tree-notification {
869
1102
  position: absolute;
870
- top: 10px;
871
- right: 10px;
1103
+ top: 70px;
1104
+ right: 15px;
872
1105
  padding: 12px 20px;
873
1106
  border-radius: 6px;
874
1107
  background: white;
@@ -4,6 +4,15 @@
4
4
  * D3.js-based tree visualization for displaying AST-based code structure.
5
5
  * Shows modules, classes, functions, and methods with complexity-based coloring.
6
6
  * Provides real-time updates during code analysis.
7
+ *
8
+ * ===== CACHE CLEAR INSTRUCTIONS =====
9
+ * If tree still moves/centers after update:
10
+ * 1. Hard refresh: Ctrl+Shift+R (Windows/Linux) or Cmd+Shift+R (Mac)
11
+ * 2. Or open DevTools (F12) → Network tab → Check "Disable cache"
12
+ * 3. Or clear browser cache: Ctrl+Shift+Delete → Clear cached images and files
13
+ *
14
+ * Version: 2025-08-29T15:30:00Z - ALL CENTERING REMOVED
15
+ * Last Update: Completely disabled tree centering/movement on node clicks
7
16
  */
8
17
 
9
18
  class CodeTree {
@@ -41,6 +50,8 @@ class CodeTree {
41
50
  this.zoom = null; // Store zoom behavior
42
51
  this.activeNode = null; // Track currently active node
43
52
  this.loadingNodes = new Set(); // Track nodes that are loading
53
+ this.bulkLoadMode = false; // Track bulk loading preference
54
+ this.expandedPaths = new Set(); // Track which paths are expanded
44
55
  }
45
56
 
46
57
  /**
@@ -280,6 +291,12 @@ class CodeTree {
280
291
 
281
292
  const container = d3.select('#code-tree-container');
282
293
  container.selectAll('*').remove();
294
+
295
+ // Add tree controls toolbar
296
+ this.addTreeControls();
297
+
298
+ // Add breadcrumb navigation
299
+ this.addBreadcrumb();
283
300
 
284
301
  if (!container || !container.node()) {
285
302
  console.error('Code tree container not found');
@@ -353,22 +370,14 @@ class CodeTree {
353
370
  });
354
371
  }
355
372
 
356
- // Add zoom behavior with proper transform handling
357
- this.zoom = d3.zoom()
358
- .scaleExtent([0.1, 10])
359
- .on('zoom', (event) => {
360
- if (this.isRadialLayout) {
361
- // Radial: maintain center point
362
- this.treeGroup.attr('transform',
363
- `translate(${centerX + event.transform.x},${centerY + event.transform.y}) scale(${event.transform.k})`);
364
- } else {
365
- // Linear: maintain left margin
366
- this.treeGroup.attr('transform',
367
- `translate(${this.margin.left + 100 + event.transform.x},${centerY + event.transform.y}) scale(${event.transform.k})`);
368
- }
369
- });
370
-
371
- this.svg.call(this.zoom);
373
+ // DISABLED: All zoom behavior has been completely disabled to prevent tree movement
374
+ // The tree should remain completely stationary - no zooming, panning, or centering allowed
375
+ this.zoom = null; // Completely disable zoom behavior
376
+
377
+ // Do NOT apply zoom behavior to SVG - this prevents all zoom/pan interactions
378
+ // this.svg.call(this.zoom); // DISABLED
379
+
380
+ console.log('[CodeTree] All zoom and pan behavior disabled - tree is now completely stationary');
372
381
 
373
382
  // Add controls overlay
374
383
  this.addVisualizationControls();
@@ -560,10 +569,285 @@ class CodeTree {
560
569
  if (this.socket) {
561
570
  this.socket.emit('code:analysis:cancel');
562
571
  }
572
+ }
573
+
574
+ /**
575
+ * Add tree control toolbar with expand/collapse and other controls
576
+ */
577
+ addTreeControls() {
578
+ const container = d3.select('#code-tree-container');
579
+
580
+ // Remove any existing controls
581
+ container.select('.tree-controls-toolbar').remove();
582
+
583
+ const toolbar = container.append('div')
584
+ .attr('class', 'tree-controls-toolbar');
585
+
586
+ // Expand All button
587
+ toolbar.append('button')
588
+ .attr('class', 'tree-control-btn')
589
+ .attr('title', 'Expand all loaded directories')
590
+ .text('⊞')
591
+ .on('click', () => this.expandAll());
592
+
593
+ // Collapse All button
594
+ toolbar.append('button')
595
+ .attr('class', 'tree-control-btn')
596
+ .attr('title', 'Collapse all directories')
597
+ .text('⊟')
598
+ .on('click', () => this.collapseAll());
599
+
600
+ // Bulk Load Toggle
601
+ toolbar.append('button')
602
+ .attr('class', 'tree-control-btn')
603
+ .attr('id', 'bulk-load-toggle')
604
+ .attr('title', 'Toggle bulk loading (load 2 levels at once)')
605
+ .text('↕')
606
+ .on('click', () => this.toggleBulkLoad());
607
+
608
+ // Layout Toggle
609
+ toolbar.append('button')
610
+ .attr('class', 'tree-control-btn')
611
+ .attr('title', 'Toggle between radial and linear layouts')
612
+ .text('◎')
613
+ .on('click', () => this.toggleLayout());
614
+
615
+ // Path Search
616
+ const searchInput = toolbar.append('input')
617
+ .attr('class', 'tree-control-btn')
618
+ .attr('type', 'text')
619
+ .attr('placeholder', 'Search...')
620
+ .attr('title', 'Search for files and directories')
621
+ .style('width', '120px')
622
+ .style('text-align', 'left')
623
+ .on('input', (event) => this.searchTree(event.target.value))
624
+ .on('keydown', (event) => {
625
+ if (event.key === 'Escape') {
626
+ event.target.value = '';
627
+ this.searchTree('');
628
+ }
629
+ });
630
+ }
631
+
632
+ /**
633
+ * Add breadcrumb navigation
634
+ */
635
+ addBreadcrumb() {
636
+ const container = d3.select('#code-tree-container');
637
+
638
+ // Remove any existing breadcrumb
639
+ container.select('.tree-breadcrumb').remove();
640
+
641
+ const breadcrumb = container.append('div')
642
+ .attr('class', 'tree-breadcrumb');
643
+
644
+ const pathDiv = breadcrumb.append('div')
645
+ .attr('class', 'breadcrumb-path')
646
+ .attr('id', 'tree-breadcrumb-path');
647
+
648
+ // Initialize with working directory
649
+ this.updateBreadcrumbPath('/');
650
+ }
563
651
 
564
- this.updateBreadcrumb('Analysis cancelled', 'warning');
565
- this.showNotification('Analysis cancelled', 'warning');
566
- this.addEventToDisplay('Analysis cancelled', 'warning');
652
+ /**
653
+ * Update breadcrumb path based on current navigation
654
+ */
655
+ updateBreadcrumbPath(currentPath) {
656
+ const pathDiv = d3.select('#tree-breadcrumb-path');
657
+ pathDiv.selectAll('*').remove();
658
+
659
+ const workingDir = this.getWorkingDirectory();
660
+ if (!workingDir || workingDir === 'Loading...' || workingDir === 'Not selected') {
661
+ pathDiv.text('No project selected');
662
+ return;
663
+ }
664
+
665
+ // Build path segments
666
+ const segments = currentPath === '/' ?
667
+ [workingDir.split('/').pop() || 'Root'] :
668
+ currentPath.split('/').filter(s => s.length > 0);
669
+
670
+ segments.forEach((segment, index) => {
671
+ if (index > 0) {
672
+ pathDiv.append('span')
673
+ .attr('class', 'breadcrumb-separator')
674
+ .text('/');
675
+ }
676
+
677
+ pathDiv.append('span')
678
+ .attr('class', index === segments.length - 1 ? 'breadcrumb-segment current' : 'breadcrumb-segment')
679
+ .text(segment)
680
+ .on('click', () => {
681
+ if (index < segments.length - 1) {
682
+ // Navigate to parent path
683
+ const parentPath = segments.slice(0, index + 1).join('/');
684
+ this.navigateToPath(parentPath);
685
+ }
686
+ });
687
+ });
688
+ }
689
+
690
+ /**
691
+ * Expand all currently loaded directories
692
+ */
693
+ expandAll() {
694
+ if (!this.root) return;
695
+
696
+ const expandNode = (node) => {
697
+ if (node.data.type === 'directory' && node.data.loaded === true) {
698
+ if (node._children) {
699
+ node.children = node._children;
700
+ node._children = null;
701
+ node.data.expanded = true;
702
+ }
703
+ }
704
+ if (node.children) {
705
+ node.children.forEach(expandNode);
706
+ }
707
+ };
708
+
709
+ expandNode(this.root);
710
+ this.update(this.root);
711
+ this.showNotification('Expanded all loaded directories', 'success');
712
+ }
713
+
714
+ /**
715
+ * Collapse all directories to root level
716
+ */
717
+ collapseAll() {
718
+ if (!this.root) return;
719
+
720
+ const collapseNode = (node) => {
721
+ if (node.data.type === 'directory' && node.children) {
722
+ node._children = node.children;
723
+ node.children = null;
724
+ node.data.expanded = false;
725
+ }
726
+ if (node._children) {
727
+ node._children.forEach(collapseNode);
728
+ }
729
+ };
730
+
731
+ collapseNode(this.root);
732
+ this.update(this.root);
733
+ this.showNotification('Collapsed all directories', 'info');
734
+ }
735
+
736
+ /**
737
+ * Toggle bulk loading mode
738
+ */
739
+ toggleBulkLoad() {
740
+ this.bulkLoadMode = !this.bulkLoadMode;
741
+ const button = d3.select('#bulk-load-toggle');
742
+
743
+ if (this.bulkLoadMode) {
744
+ button.classed('active', true);
745
+ this.showNotification('Bulk load enabled - will load 2 levels deep', 'info');
746
+ } else {
747
+ button.classed('active', false);
748
+ this.showNotification('Bulk load disabled - load 1 level at a time', 'info');
749
+ }
750
+ }
751
+
752
+ /**
753
+ * Navigate to a specific path in the tree
754
+ */
755
+ navigateToPath(path) {
756
+ // Implementation for navigating to a specific path
757
+ // This would expand the tree to show the specified path
758
+ this.updateBreadcrumbPath(path);
759
+ this.showNotification(`Navigating to: ${path}`, 'info');
760
+ }
761
+
762
+ /**
763
+ * Search the tree for matching files/directories
764
+ */
765
+ searchTree(query) {
766
+ if (!this.root || !this.treeGroup) return;
767
+
768
+ const searchTerm = query.toLowerCase().trim();
769
+
770
+ // Clear previous search highlights
771
+ this.treeGroup.selectAll('.code-node')
772
+ .classed('search-match', false);
773
+
774
+ if (!searchTerm) {
775
+ return; // No search term, just clear highlights
776
+ }
777
+
778
+ // Find matching nodes
779
+ const matchingNodes = [];
780
+ const searchNode = (node) => {
781
+ const name = (node.data.name || '').toLowerCase();
782
+ const path = (node.data.path || '').toLowerCase();
783
+
784
+ if (name.includes(searchTerm) || path.includes(searchTerm)) {
785
+ matchingNodes.push(node);
786
+ }
787
+
788
+ if (node.children) {
789
+ node.children.forEach(searchNode);
790
+ }
791
+ if (node._children) {
792
+ node._children.forEach(searchNode);
793
+ }
794
+ };
795
+
796
+ searchNode(this.root);
797
+
798
+ // Highlight matching nodes
799
+ if (matchingNodes.length > 0) {
800
+ // Get all current nodes in the tree
801
+ const allNodes = this.treeGroup.selectAll('.code-node').data();
802
+
803
+ matchingNodes.forEach(matchNode => {
804
+ // Find the corresponding DOM node
805
+ const domNode = this.treeGroup.selectAll('.code-node')
806
+ .filter(d => d.data.path === matchNode.data.path);
807
+ domNode.classed('search-match', true);
808
+
809
+ // Expand parent path to show the match
810
+ this.expandPathToNode(matchNode);
811
+ });
812
+
813
+ this.showNotification(`Found ${matchingNodes.length} matches`, 'success');
814
+
815
+ // Auto-center on first match if in radial layout - REMOVED
816
+ // Centering functionality has been disabled to prevent unwanted repositioning
817
+ // if (matchingNodes.length > 0 && this.isRadialLayout) {
818
+ // this.centerOnNode ? this.centerOnNode(matchingNodes[0]) : this.centerOnNodeRadial(matchingNodes[0]);
819
+ // }
820
+ } else {
821
+ this.showNotification('No matches found', 'info');
822
+ }
823
+ }
824
+
825
+ /**
826
+ * Expand the tree path to show a specific node
827
+ */
828
+ expandPathToNode(targetNode) {
829
+ const pathToExpand = [];
830
+ let current = targetNode.parent;
831
+
832
+ // Build path from node to root
833
+ while (current && current !== this.root) {
834
+ pathToExpand.unshift(current);
835
+ current = current.parent;
836
+ }
837
+
838
+ // Expand each node in the path
839
+ pathToExpand.forEach(node => {
840
+ if (node.data.type === 'directory' && node._children) {
841
+ node.children = node._children;
842
+ node._children = null;
843
+ node.data.expanded = true;
844
+ }
845
+ });
846
+
847
+ // Update the visualization if we expanded anything
848
+ if (pathToExpand.length > 0) {
849
+ this.update(this.root);
850
+ }
567
851
  }
568
852
 
569
853
  /**
@@ -660,6 +944,8 @@ class CodeTree {
660
944
  const d3Node = this.findD3NodeByPath(searchPath);
661
945
  if (d3Node && this.loadingNodes.has(searchPath)) {
662
946
  this.removeLoadingPulse(d3Node);
947
+ this.loadingNodes.delete(searchPath); // Remove from loading set
948
+ console.log('🎯 [SUBDIRECTORY LOADING] Successfully completed and removed from loading set:', searchPath);
663
949
  }
664
950
  node.children = data.children.map(child => {
665
951
  // Construct full path for child by combining parent path with child name
@@ -884,12 +1170,13 @@ class CodeTree {
884
1170
  // Add to events display
885
1171
  this.addEventToDisplay(`📁 Found ${(data.children || []).length} items in: ${data.name || data.path}`, 'info');
886
1172
 
887
- console.log('📥 Received directory discovery:', {
1173
+ console.log(' [SUBDIRECTORY LOADING] Received directory discovery response:', {
888
1174
  path: data.path,
889
1175
  name: data.name,
890
1176
  childrenCount: (data.children || []).length,
891
1177
  children: (data.children || []).map(c => ({ name: c.name, type: c.type })),
892
- workingDir: this.getWorkingDirectory()
1178
+ workingDir: this.getWorkingDirectory(),
1179
+ fullEventData: data
893
1180
  });
894
1181
 
895
1182
  // Convert absolute path back to relative path to match tree nodes
@@ -948,6 +1235,8 @@ class CodeTree {
948
1235
  // Remove loading animation
949
1236
  if (this.loadingNodes.has(searchPath)) {
950
1237
  this.removeLoadingPulse(d3Node);
1238
+ this.loadingNodes.delete(searchPath); // Remove from loading set
1239
+ console.log('🎯 [SUBDIRECTORY LOADING] Successfully completed and removed from loading set (hierarchy update):', searchPath);
951
1240
  }
952
1241
  }
953
1242
 
@@ -979,11 +1268,32 @@ class CodeTree {
979
1268
  this.update(this.root);
980
1269
  }
981
1270
 
982
- this.updateBreadcrumb(`Loaded ${node.children.length} items from ${node.name}`, 'success');
1271
+ // Provide better feedback for empty vs populated directories
1272
+ if (node.children.length === 0) {
1273
+ this.updateBreadcrumb(`Empty directory: ${node.name}`, 'info');
1274
+ this.showNotification(`Directory "${node.name}" is empty`, 'info');
1275
+ } else {
1276
+ this.updateBreadcrumb(`Loaded ${node.children.length} items from ${node.name}`, 'success');
1277
+ this.showNotification(`Loaded ${node.children.length} items from "${node.name}"`, 'success');
1278
+ }
983
1279
  this.updateStats();
984
1280
  } else if (!node) {
1281
+ console.error('❌ [SUBDIRECTORY LOADING] Node not found for path:', {
1282
+ searchPath,
1283
+ originalPath: data.path,
1284
+ workingDir: this.getWorkingDirectory(),
1285
+ allTreePaths: this.getAllTreePaths(this.treeData)
1286
+ });
1287
+ this.showNotification(`Could not find directory "${searchPath}" in tree`, 'error');
985
1288
  this.logAllPaths(this.treeData);
986
1289
  } else if (node && !data.children) {
1290
+ console.warn('⚠️ [SUBDIRECTORY LOADING] Directory response has no children:', {
1291
+ path: data.path,
1292
+ searchPath,
1293
+ nodeExists: !!node,
1294
+ dataKeys: Object.keys(data),
1295
+ fullData: data
1296
+ });
987
1297
  // This might be a top-level directory discovery
988
1298
  const pathParts = data.path ? data.path.split('/').filter(p => p) : [];
989
1299
  const isTopLevel = pathParts.length === 1;
@@ -1044,6 +1354,7 @@ class CodeTree {
1044
1354
  const d3Node = this.findD3NodeByPath(data.path);
1045
1355
  if (d3Node && this.loadingNodes.has(data.path)) {
1046
1356
  this.removeLoadingPulse(d3Node);
1357
+ this.loadingNodes.delete(data.path); // Remove from loading set
1047
1358
  }
1048
1359
  // Update activity ticker
1049
1360
  if (data.path) {
@@ -1448,11 +1759,11 @@ class CodeTree {
1448
1759
  findNodeByPath(path, node = null) {
1449
1760
  if (!node) {
1450
1761
  node = this.treeData;
1451
- // Searching for node by path
1452
- // Root node identified
1762
+ console.log('🔍 [SUBDIRECTORY LOADING] Starting search for path:', path);
1453
1763
  }
1454
1764
 
1455
1765
  if (node.path === path) {
1766
+ console.log('✅ [SUBDIRECTORY LOADING] Found node for path:', path);
1456
1767
  return node;
1457
1768
  }
1458
1769
 
@@ -1465,8 +1776,8 @@ class CodeTree {
1465
1776
  }
1466
1777
  }
1467
1778
 
1468
- if (!node.parent) {
1469
- // Node path not found in current tree structure
1779
+ if (!node.parent && node === this.treeData) {
1780
+ console.warn('❌ [SUBDIRECTORY LOADING] Path not found in tree:', path);
1470
1781
  }
1471
1782
  return null;
1472
1783
  }
@@ -1483,6 +1794,19 @@ class CodeTree {
1483
1794
  }
1484
1795
  }
1485
1796
 
1797
+ /**
1798
+ * Helper to collect all paths in tree for debugging
1799
+ */
1800
+ getAllTreePaths(node) {
1801
+ const paths = [node.path];
1802
+ if (node.children) {
1803
+ for (const child of node.children) {
1804
+ paths.push(...this.getAllTreePaths(child));
1805
+ }
1806
+ }
1807
+ return paths;
1808
+ }
1809
+
1486
1810
  /**
1487
1811
  * Find D3 hierarchy node by path
1488
1812
  */
@@ -1669,7 +1993,24 @@ class CodeTree {
1669
1993
 
1670
1994
  // Enter new nodes
1671
1995
  const nodeEnter = node.enter().append('g')
1672
- .attr('class', 'node')
1996
+ .attr('class', d => {
1997
+ let classes = ['node', 'code-node'];
1998
+ if (d.data.type === 'directory') {
1999
+ classes.push('directory');
2000
+ if (d.data.loaded === true && d.children) {
2001
+ classes.push('expanded');
2002
+ }
2003
+ if (d.data.loaded === 'loading') {
2004
+ classes.push('loading');
2005
+ }
2006
+ if (d.data.children && d.data.children.length === 0) {
2007
+ classes.push('empty');
2008
+ }
2009
+ } else if (d.data.type === 'file') {
2010
+ classes.push('file');
2011
+ }
2012
+ return classes.join(' ');
2013
+ })
1673
2014
  .attr('transform', d => {
1674
2015
  if (this.isRadialLayout) {
1675
2016
  const [x, y] = this.radialPoint(source.x0 || 0, source.y0 || 0);
@@ -1686,9 +2027,27 @@ class CodeTree {
1686
2027
  .attr('r', 1e-6)
1687
2028
  .style('fill', d => this.getNodeColor(d))
1688
2029
  .style('stroke', d => this.getNodeStrokeColor(d))
1689
- .style('stroke-width', 2)
2030
+ .style('stroke-width', d => d.data.type === 'directory' ? 2 : 1.5)
2031
+ .style('cursor', 'pointer') // Add cursor pointer for visual feedback
2032
+ .on('click', (event, d) => this.onNodeClick(event, d)) // CRITICAL FIX: Add click handler to circles
1690
2033
  .on('mouseover', (event, d) => this.showTooltip(event, d))
1691
2034
  .on('mouseout', () => this.hideTooltip());
2035
+
2036
+ // Add expand/collapse icons for directories
2037
+ nodeEnter.filter(d => d.data.type === 'directory')
2038
+ .append('text')
2039
+ .attr('class', 'expand-icon')
2040
+ .attr('x', 0)
2041
+ .attr('y', 0)
2042
+ .attr('text-anchor', 'middle')
2043
+ .attr('dominant-baseline', 'central')
2044
+ .text(d => {
2045
+ if (d.data.loaded === 'loading') return '⟳';
2046
+ if (d.data.loaded === true && d.children) return '▼';
2047
+ return '▶';
2048
+ })
2049
+ .style('font-size', '10px')
2050
+ .style('pointer-events', 'none');
1692
2051
 
1693
2052
  // Add labels for nodes with smart positioning
1694
2053
  nodeEnter.append('text')
@@ -1721,21 +2080,46 @@ class CodeTree {
1721
2080
  .style('fill-opacity', 1e-6)
1722
2081
  .style('font-size', '12px')
1723
2082
  .style('font-family', '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif')
1724
- .style('text-shadow', '1px 1px 2px rgba(255,255,255,0.8), -1px -1px 2px rgba(255,255,255,0.8)');
2083
+ .style('text-shadow', '1px 1px 2px rgba(255,255,255,0.8), -1px -1px 2px rgba(255,255,255,0.8)')
2084
+ .on('click', (event, d) => this.onNodeClick(event, d)) // CRITICAL FIX: Add click handler to labels
2085
+ .style('cursor', 'pointer');
1725
2086
 
1726
- // Add icons for node types
1727
- nodeEnter.append('text')
2087
+ // Add icons for node types (files only, directories use expand icons)
2088
+ nodeEnter.filter(d => d.data.type !== 'directory')
2089
+ .append('text')
1728
2090
  .attr('class', 'node-icon')
1729
2091
  .attr('dy', '.35em')
1730
2092
  .attr('x', 0)
1731
2093
  .attr('text-anchor', 'middle')
1732
2094
  .text(d => this.getNodeIcon(d))
1733
2095
  .style('font-size', '10px')
1734
- .style('fill', 'white');
2096
+ .style('fill', 'white')
2097
+ .on('click', (event, d) => this.onNodeClick(event, d)) // CRITICAL FIX: Add click handler to file icons
2098
+ .style('cursor', 'pointer');
2099
+
2100
+ // Add item count badges for directories
2101
+ nodeEnter.filter(d => d.data.type === 'directory' && d.data.children)
2102
+ .append('text')
2103
+ .attr('class', 'item-count-badge')
2104
+ .attr('x', 12)
2105
+ .attr('y', -8)
2106
+ .attr('text-anchor', 'middle')
2107
+ .text(d => {
2108
+ const count = d.data.children ? d.data.children.length : 0;
2109
+ return count > 0 ? count : '';
2110
+ })
2111
+ .style('font-size', '9px')
2112
+ .style('opacity', 0.7)
2113
+ .on('click', (event, d) => this.onNodeClick(event, d)) // CRITICAL FIX: Add click handler to count badges
2114
+ .style('cursor', 'pointer');
1735
2115
 
1736
2116
  // Transition to new positions
1737
2117
  const nodeUpdate = nodeEnter.merge(node);
1738
2118
 
2119
+ // CRITICAL FIX: Ensure ALL nodes (new and existing) have click handlers
2120
+ // This fixes the issue where subdirectory clicks stop working after tree updates
2121
+ nodeUpdate.on('click', (event, d) => this.onNodeClick(event, d));
2122
+
1739
2123
  nodeUpdate.transition()
1740
2124
  .duration(this.duration)
1741
2125
  .attr('transform', d => {
@@ -1747,9 +2131,45 @@ class CodeTree {
1747
2131
  }
1748
2132
  });
1749
2133
 
2134
+ // Update node classes based on current state
2135
+ nodeUpdate.attr('class', d => {
2136
+ let classes = ['node', 'code-node'];
2137
+ if (d.data.type === 'directory') {
2138
+ classes.push('directory');
2139
+ if (d.data.loaded === true && d.children) {
2140
+ classes.push('expanded');
2141
+ }
2142
+ if (d.data.loaded === 'loading') {
2143
+ classes.push('loading');
2144
+ }
2145
+ if (d.data.children && d.data.children.length === 0) {
2146
+ classes.push('empty');
2147
+ }
2148
+ } else if (d.data.type === 'file') {
2149
+ classes.push('file');
2150
+ }
2151
+ return classes.join(' ');
2152
+ });
2153
+
1750
2154
  nodeUpdate.select('circle.node-circle')
1751
- .attr('r', 8)
2155
+ .attr('r', d => d.data.type === 'directory' ? 10 : 8)
1752
2156
  .style('fill', d => this.getNodeColor(d))
2157
+
2158
+ // Update expand/collapse icons
2159
+ nodeUpdate.select('.expand-icon')
2160
+ .text(d => {
2161
+ if (d.data.loaded === 'loading') return '⟳';
2162
+ if (d.data.loaded === true && d.children) return '▼';
2163
+ return '▶';
2164
+ });
2165
+
2166
+ // Update item count badges
2167
+ nodeUpdate.select('.item-count-badge')
2168
+ .text(d => {
2169
+ if (d.data.type !== 'directory') return '';
2170
+ const count = d.data.children ? d.data.children.length : 0;
2171
+ return count > 0 ? count : '';
2172
+ })
1753
2173
  .style('stroke', d => this.getNodeStrokeColor(d))
1754
2174
  .attr('cursor', 'pointer');
1755
2175
 
@@ -1861,67 +2281,25 @@ class CodeTree {
1861
2281
  }
1862
2282
 
1863
2283
  /**
1864
- * Center the view on a specific node (Linear layout)
2284
+ * REMOVED: Center the view on a specific node (Linear layout)
2285
+ * This method has been completely disabled to prevent unwanted tree movement.
2286
+ * All centering functionality has been removed from the code tree.
1865
2287
  */
1866
2288
  centerOnNode(d) {
1867
- if (!this.svg || !this.zoom) return;
1868
-
1869
- // Get current transform or use default zoom level
1870
- const currentTransform = d3.zoomTransform(this.svg.node());
1871
- // Zoom in to 2x for better focus on clicked node
1872
- const targetScale = currentTransform.k < 2 ? 2 : currentTransform.k;
1873
-
1874
- // Account for the initial tree group offset
1875
- const initialOffsetX = this.margin.left + 100;
1876
- const initialOffsetY = this.height / 2;
1877
-
1878
- // Calculate position to center the node accounting for the tree group's transform
1879
- const x = initialOffsetX - d.y * targetScale + this.width / 2;
1880
- const y = initialOffsetY - d.x * targetScale + this.height / 2;
1881
-
1882
- this.svg.transition()
1883
- .duration(750)
1884
- .call(
1885
- this.zoom.transform,
1886
- d3.zoomIdentity
1887
- .translate(x, y)
1888
- .scale(targetScale)
1889
- );
2289
+ // Method disabled - no centering operations will be performed
2290
+ console.log('[CodeTree] centerOnNode called but disabled - no centering will occur');
2291
+ return;
1890
2292
  }
1891
2293
 
1892
2294
  /**
1893
- * Center the view on a specific node (Radial layout)
2295
+ * REMOVED: Center the view on a specific node (Radial layout)
2296
+ * This method has been completely disabled to prevent unwanted tree movement.
2297
+ * All centering functionality has been removed from the code tree.
1894
2298
  */
1895
2299
  centerOnNodeRadial(d) {
1896
- if (!this.svg || !this.zoom) return;
1897
-
1898
- // Use the same radialPoint function for consistency
1899
- const [x, y] = this.radialPoint(d.x, d.y);
1900
-
1901
- // Get current transform or use default zoom level
1902
- const currentTransform = d3.zoomTransform(this.svg.node());
1903
- // Zoom in to 2x for better focus on clicked node
1904
- const targetScale = currentTransform.k < 2 ? 2 : currentTransform.k;
1905
-
1906
- // Account for the initial tree group centering
1907
- const centerX = this.width / 2;
1908
- const centerY = this.height / 2;
1909
-
1910
- // Calculate translation to center the node
1911
- // The tree group is centered at centerX, centerY
1912
- // We need to offset by the node's position scaled
1913
- const targetX = centerX - x * targetScale;
1914
- const targetY = centerY - y * targetScale;
1915
-
1916
- // Apply smooth transition to center the node with zoom
1917
- this.svg.transition()
1918
- .duration(750)
1919
- .call(
1920
- this.zoom.transform,
1921
- d3.zoomIdentity
1922
- .translate(targetX, targetY)
1923
- .scale(targetScale)
1924
- );
2300
+ // Method disabled - no centering operations will be performed
2301
+ console.log('[CodeTree] centerOnNodeRadial called but disabled - no centering will occur');
2302
+ return;
1925
2303
  }
1926
2304
 
1927
2305
  /**
@@ -2058,43 +2436,15 @@ class CodeTree {
2058
2436
  .style('stroke-width', 3)
2059
2437
  .style('opacity', 0.8);
2060
2438
 
2061
- // For radial, adjust zoom to show both parent and clicked node
2062
- if (this.isRadialLayout && d.parent) {
2063
- // Calculate bounding box including parent and immediate children
2064
- const nodes = [d, d.parent];
2065
- if (d.children) nodes.push(...d.children);
2066
- else if (d._children) nodes.push(...d._children);
2067
-
2068
- const angles = nodes.map(n => n.x);
2069
- const radii = nodes.map(n => n.y);
2070
-
2071
- const minAngle = Math.min(...angles);
2072
- const maxAngle = Math.max(...angles);
2073
- const maxRadius = Math.max(...radii);
2074
-
2075
- // Zoom to fit parent and children
2076
- const angleSpan = maxAngle - minAngle;
2077
- const scale = Math.min(
2078
- angleSpan > 0 ? (Math.PI * 2) / (angleSpan * 2) : 2.5, // Fit angle span
2079
- this.width / (2 * maxRadius), // Fit radius
2080
- 2.5 // Max zoom
2081
- );
2082
-
2083
- // Calculate center angle and radius
2084
- const centerAngle = (minAngle + maxAngle) / 2;
2085
- const centerRadius = maxRadius / 2;
2086
- const centerX = centerRadius * Math.cos(centerAngle - Math.PI / 2);
2087
- const centerY = centerRadius * Math.sin(centerAngle - Math.PI / 2);
2088
-
2089
- this.svg.transition()
2090
- .duration(750)
2091
- .call(
2092
- this.zoom.transform,
2093
- d3.zoomIdentity
2094
- .translate(this.width / 2 - centerX * scale, this.height / 2 - centerY * scale)
2095
- .scale(scale)
2096
- );
2097
- }
2439
+ // REMOVED: Radial zoom adjustment functionality
2440
+ // This section previously adjusted zoom to show parent and clicked node together,
2441
+ // but has been completely disabled to prevent unwanted tree movement/centering.
2442
+ // Only visual highlighting of the parent remains active.
2443
+
2444
+ // if (this.isRadialLayout && d.parent) {
2445
+ // // All zoom.transform operations have been disabled
2446
+ // // to prevent tree movement when nodes are clicked
2447
+ // }
2098
2448
  }
2099
2449
 
2100
2450
  /**
@@ -2133,24 +2483,26 @@ class CodeTree {
2133
2483
  // These execute immediately before any async operations
2134
2484
 
2135
2485
 
2136
- // Center on clicked node (immediate visual effect)
2137
- try {
2138
- if (this.isRadialLayout) {
2139
- if (typeof this.centerOnNodeRadial === 'function') {
2140
- this.centerOnNodeRadial(d);
2141
- } else {
2142
- console.error('[CodeTree] centerOnNodeRadial is not a function!');
2143
- }
2144
- } else {
2145
- if (typeof this.centerOnNode === 'function') {
2146
- this.centerOnNode(d);
2147
- } else {
2148
- console.error('[CodeTree] centerOnNode is not a function!');
2149
- }
2150
- }
2151
- } catch (error) {
2152
- console.error('[CodeTree] ERROR during centering:', error, error.stack);
2153
- }
2486
+ // Center on clicked node (immediate visual effect) - REMOVED
2487
+ // Centering functionality has been disabled to prevent unwanted repositioning
2488
+ // when nodes are clicked. All other click functionality remains intact.
2489
+ // try {
2490
+ // if (this.isRadialLayout) {
2491
+ // if (typeof this.centerOnNodeRadial === 'function') {
2492
+ // this.centerOnNodeRadial(d);
2493
+ // } else {
2494
+ // console.error('[CodeTree] centerOnNodeRadial is not a function!');
2495
+ // }
2496
+ // } else {
2497
+ // if (typeof this.centerOnNode === 'function') {
2498
+ // this.centerOnNode(d);
2499
+ // } else {
2500
+ // console.error('[CodeTree] centerOnNode is not a function!');
2501
+ // }
2502
+ // }
2503
+ // } catch (error) {
2504
+ // console.error('[CodeTree] ERROR during centering:', error, error.stack);
2505
+ // }
2154
2506
 
2155
2507
 
2156
2508
  // Highlight with larger icon (immediate visual effect)
@@ -2213,12 +2565,29 @@ class CodeTree {
2213
2565
 
2214
2566
  // For directories that haven't been loaded yet, request discovery
2215
2567
  if (d.data.type === 'directory' && !d.data.loaded) {
2568
+ // Prevent duplicate requests
2569
+ if (this.loadingNodes.has(d.data.path)) {
2570
+ this.showNotification(`Already loading: ${d.data.name}`, 'warning');
2571
+ return;
2572
+ }
2573
+
2216
2574
  // Mark as loading immediately to prevent duplicate requests
2217
2575
  d.data.loaded = 'loading';
2576
+ this.loadingNodes.add(d.data.path);
2218
2577
 
2219
2578
  // Ensure path is absolute or relative to working directory
2220
2579
  const fullPath = this.ensureFullPath(d.data.path);
2221
2580
 
2581
+ // CRITICAL DEBUG: Log directory loading attempt
2582
+ console.log('🚀 [SUBDIRECTORY LOADING] Attempting to load:', {
2583
+ originalPath: d.data.path,
2584
+ fullPath: fullPath,
2585
+ nodeType: d.data.type,
2586
+ loaded: d.data.loaded,
2587
+ hasSocket: !!this.socket,
2588
+ workingDir: this.getWorkingDirectory()
2589
+ });
2590
+
2222
2591
  // Sending discovery request for child content
2223
2592
 
2224
2593
  // Store reference to the D3 node for later expansion
@@ -2229,9 +2598,19 @@ class CodeTree {
2229
2598
 
2230
2599
  // Request directory contents via Socket.IO
2231
2600
  if (this.socket) {
2601
+ console.log('📡 [SUBDIRECTORY LOADING] Emitting WebSocket request:', {
2602
+ event: 'code:discover:directory',
2603
+ data: {
2604
+ path: fullPath,
2605
+ depth: this.bulkLoadMode ? 2 : 1,
2606
+ languages: selectedLanguages,
2607
+ ignore_patterns: ignorePatterns
2608
+ }
2609
+ });
2610
+
2232
2611
  this.socket.emit('code:discover:directory', {
2233
2612
  path: fullPath,
2234
- depth: 1, // Only get immediate children
2613
+ depth: this.bulkLoadMode ? 2 : 1, // Load 2 levels if bulk mode enabled
2235
2614
  languages: selectedLanguages,
2236
2615
  ignore_patterns: ignorePatterns
2237
2616
  });
@@ -2239,6 +2618,8 @@ class CodeTree {
2239
2618
  this.updateBreadcrumb(`Loading ${d.data.name}...`, 'info');
2240
2619
  this.showNotification(`Loading directory: ${d.data.name}`, 'info');
2241
2620
  } else {
2621
+ console.error('❌ [SUBDIRECTORY LOADING] No WebSocket connection available!');
2622
+ this.showNotification(`Cannot load directory: No connection`, 'error');
2242
2623
  }
2243
2624
  }, 100); // 100ms delay to ensure visual effects render first
2244
2625
  }
@@ -2589,109 +2970,22 @@ class CodeTree {
2589
2970
  * Reset zoom to fit the tree
2590
2971
  */
2591
2972
  resetZoom() {
2592
- if (!this.svg || !this.zoom) return;
2593
-
2594
- // Reset to identity transform for radial layout (centered)
2595
- this.svg.transition()
2596
- .duration(750)
2597
- .call(
2598
- this.zoom.transform,
2599
- d3.zoomIdentity
2600
- );
2601
-
2602
- this.showNotification('Zoom reset', 'info');
2973
+ // DISABLED: All zoom reset operations have been disabled to prevent tree centering/movement
2974
+ // The tree should remain stationary and not center/move when interacting with nodes
2975
+ console.log('[CodeTree] resetZoom called but disabled - no zoom reset will occur');
2976
+ this.showNotification('Zoom reset disabled - tree remains stationary', 'info');
2977
+ return;
2603
2978
  }
2604
2979
 
2605
2980
  /**
2606
- * Focus on a specific node and its subtree
2981
+ * REMOVED: Focus on a specific node and its subtree
2982
+ * This method has been completely disabled to prevent unwanted tree movement.
2983
+ * All centering and focus functionality has been removed from the code tree.
2607
2984
  */
2608
2985
  focusOnNode(node) {
2609
- if (!this.svg || !this.zoom || !node) return;
2610
-
2611
- // Get all descendants of this node
2612
- const descendants = node.descendants ? node.descendants() : [node];
2613
-
2614
- if (this.isRadialLayout) {
2615
- // For radial layout, calculate the bounding box in polar coordinates
2616
- const angles = descendants.map(d => d.x);
2617
- const radii = descendants.map(d => d.y);
2618
-
2619
- const minAngle = Math.min(...angles);
2620
- const maxAngle = Math.max(...angles);
2621
- const minRadius = Math.min(...radii);
2622
- const maxRadius = Math.max(...radii);
2623
-
2624
- // Convert polar bounds to Cartesian for centering
2625
- const centerAngle = (minAngle + maxAngle) / 2;
2626
- const centerRadius = (minRadius + maxRadius) / 2;
2627
-
2628
- // Convert to Cartesian coordinates
2629
- const centerX = centerRadius * Math.cos(centerAngle - Math.PI / 2);
2630
- const centerY = centerRadius * Math.sin(centerAngle - Math.PI / 2);
2631
-
2632
- // Calculate the span for zoom scale
2633
- const angleSpan = maxAngle - minAngle;
2634
- const radiusSpan = maxRadius - minRadius;
2635
-
2636
- // Calculate scale to fit the subtree
2637
- // Use angle span to determine scale (radial layout specific)
2638
- let scale = 1;
2639
- if (angleSpan > 0 && radiusSpan > 0) {
2640
- // Scale based on the larger dimension
2641
- const angleFactor = Math.PI * 2 / angleSpan; // Full circle / angle span
2642
- const radiusFactor = this.radius / radiusSpan;
2643
- scale = Math.min(angleFactor, radiusFactor, 3); // Max zoom of 3x
2644
- scale = Math.max(scale, 1); // Min zoom of 1x
2645
- }
2646
-
2647
- // Animate the zoom and center
2648
- this.svg.transition()
2649
- .duration(750)
2650
- .call(
2651
- this.zoom.transform,
2652
- d3.zoomIdentity
2653
- .translate(this.width/2 - centerX * scale, this.height/2 - centerY * scale)
2654
- .scale(scale)
2655
- );
2656
-
2657
- } else {
2658
- // For linear/tree layout
2659
- const xValues = descendants.map(d => d.x);
2660
- const yValues = descendants.map(d => d.y);
2661
-
2662
- const minX = Math.min(...xValues);
2663
- const maxX = Math.max(...xValues);
2664
- const minY = Math.min(...yValues);
2665
- const maxY = Math.max(...yValues);
2666
-
2667
- // Calculate center
2668
- const centerX = (minX + maxX) / 2;
2669
- const centerY = (minY + maxY) / 2;
2670
-
2671
- // Calculate bounds
2672
- const width = maxX - minX;
2673
- const height = maxY - minY;
2674
-
2675
- // Calculate scale to fit
2676
- const padding = 100;
2677
- let scale = 1;
2678
- if (width > 0 && height > 0) {
2679
- const scaleX = (this.width - padding) / width;
2680
- const scaleY = (this.height - padding) / height;
2681
- scale = Math.min(scaleX, scaleY, 2.5); // Max zoom of 2.5x
2682
- scale = Math.max(scale, 0.5); // Min zoom of 0.5x
2683
- }
2684
-
2685
- // Animate zoom to focus
2686
- this.svg.transition()
2687
- .duration(750)
2688
- .call(
2689
- this.zoom.transform,
2690
- d3.zoomIdentity
2691
- .translate(this.width/2 - centerX * scale, this.height/2 - centerY * scale)
2692
- .scale(scale)
2693
- );
2694
- }
2986
+ // Method disabled - no focusing/centering operations will be performed
2987
+ console.log('[CodeTree] focusOnNode called but disabled - no focusing will occur');
2988
+ return;
2695
2989
 
2696
2990
  // Update breadcrumb with focused path
2697
2991
  const path = this.getNodePath(node);
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 4.1.13
3
+ Version: 4.1.14
4
4
  Summary: Claude Multi-Agent Project Manager - Orchestrate Claude with agent delegation and ticket tracking
5
5
  Author-email: Bob Matsuoka <bob@matsuoka.com>
6
6
  Maintainer: Claude MPM Team
@@ -1,5 +1,5 @@
1
1
  claude_mpm/BUILD_NUMBER,sha256=toytnNjkIKPgQaGwDqQdC1rpNTAdSEc6Vja50d7Ovug,4
2
- claude_mpm/VERSION,sha256=E1InPHCtwH8S_MOiQtRRNQYYpQcw7o4xWnOYO1oirn0,7
2
+ claude_mpm/VERSION,sha256=sAWQ1JyXU3b9eFcjVh2abG2B2O4q2zU4-5wBB_cdSLo,7
3
3
  claude_mpm/__init__.py,sha256=lyTZAYGH4DTaFGLRNWJKk5Q5oTjzN5I6AXmfVX-Jff0,1512
4
4
  claude_mpm/__main__.py,sha256=Ro5UBWBoQaSAIoSqWAr7zkbLyvi4sSy28WShqAhKJG0,723
5
5
  claude_mpm/constants.py,sha256=I946iCQzIIPRZVVJ8aO7lA4euiyDnNw2IX7EelAOkIE,5915
@@ -179,8 +179,8 @@ claude_mpm/dashboard/static/built/components/session-manager.js,sha256=ZG__csNeB
179
179
  claude_mpm/dashboard/static/built/components/socket-manager.js,sha256=LEqCS0_EABAsQVUfb6WQk152mSicK2k039zne5cKR8A,131
180
180
  claude_mpm/dashboard/static/built/components/ui-state-manager.js,sha256=PtZs6sxNhqMMFwdlr04kDKQbgOvxtMHdjSh56KR2ZBo,134
181
181
  claude_mpm/dashboard/static/built/components/working-directory.js,sha256=xE1ydpKDzRWrzHzfjrCiq5wbf3vDhmgQTGKS7myQcPM,15790
182
- claude_mpm/dashboard/static/css/activity.css,sha256=7RQBekJLMIcavAHBWUsP5CTUV-GmjUbWKsRRowrl7Eo,29093
183
- claude_mpm/dashboard/static/css/code-tree.css,sha256=xgWxg5yWOeJhiZ8eirxri6JHETxQs8SQDSv3yYtdgfY,20894
182
+ claude_mpm/dashboard/static/css/activity.css,sha256=ClwqYuLrq7X0-Uj8jVuMFUvsr7BPtacaeaxLoPM-nAo,29141
183
+ claude_mpm/dashboard/static/css/code-tree.css,sha256=x0MlVKrBBYr7XU8ndhxx7cjCe35GouhthIM32Zc9SA8,25599
184
184
  claude_mpm/dashboard/static/css/connection-status.css,sha256=nQiMLxIFjY5MDgrVCG58VR5H1PpE1vLlgXmnn01-P64,6729
185
185
  claude_mpm/dashboard/static/css/dashboard.css,sha256=7QlDMl1GKluf2MA_jlijTUVlMlK0RgdyfS1RLD7uv9k,75201
186
186
  claude_mpm/dashboard/static/dist/dashboard.js,sha256=kShaKMMdwk1cKcHnXsn-3kLfYMHI14HUgGu_QJQpzZc,52792
@@ -209,7 +209,7 @@ claude_mpm/dashboard/static/js/components/activity-tree.js,sha256=358pc-N6lrJ1bf
209
209
  claude_mpm/dashboard/static/js/components/agent-hierarchy.js,sha256=Xihxog_vJrk8VBEkDogV_wbye2GIFWmH71VQ1lETOHk,28243
210
210
  claude_mpm/dashboard/static/js/components/agent-inference.js,sha256=RUVZ_fLOyDkHYjrROen_Pzzay79Bh29eXp_GRIPbIRg,37493
211
211
  claude_mpm/dashboard/static/js/components/build-tracker.js,sha256=iouv35tNhnyx9UKtD7X1eakJkpCnvZVCrAJ_VdzsKUY,11251
212
- claude_mpm/dashboard/static/js/components/code-tree.js,sha256=Miz1rHQnRKk416fWVM15oRbrg3P6mhPMCfifDcrIlq0,105246
212
+ claude_mpm/dashboard/static/js/components/code-tree.js,sha256=bLLU7MBZmTccIa3h3WCAyEwsyhRn5jicgJ7rpPPAYxQ,117432
213
213
  claude_mpm/dashboard/static/js/components/code-viewer.js,sha256=vhesEPYOM6MggweaYvYsv7ufVbuVpIcyJPXpJXyJwpM,14453
214
214
  claude_mpm/dashboard/static/js/components/connection-debug.js,sha256=Qxr_ofDNkxDlZAwbLnhZkXVMyuO9jOe-NMWC9VHxNnA,22196
215
215
  claude_mpm/dashboard/static/js/components/event-processor.js,sha256=_GnAz8pxN1iyXw0O4AIR482QFyQAigEKO9IDUOUbGqc,24844
@@ -582,9 +582,9 @@ claude_mpm/utils/subprocess_utils.py,sha256=zgiwLqh_17WxHpySvUPH65pb4bzIeUGOAYUJ
582
582
  claude_mpm/validation/__init__.py,sha256=YZhwE3mhit-lslvRLuwfX82xJ_k4haZeKmh4IWaVwtk,156
583
583
  claude_mpm/validation/agent_validator.py,sha256=3Lo6LK-Mw9IdnL_bd3zl_R6FkgSVDYKUUM7EeVVD3jc,20865
584
584
  claude_mpm/validation/frontmatter_validator.py,sha256=u8g4Eyd_9O6ugj7Un47oSGh3kqv4wMkuks2i_CtWRvM,7028
585
- claude_mpm-4.1.13.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
586
- claude_mpm-4.1.13.dist-info/METADATA,sha256=evsLnQuIHu_It8VWFFH-ZssK4rbm83BsTHUI6vganjo,13419
587
- claude_mpm-4.1.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
588
- claude_mpm-4.1.13.dist-info/entry_points.txt,sha256=FDPZgz8JOvD-6iuXY2l9Zbo9zYVRuE4uz4Qr0vLeGOk,471
589
- claude_mpm-4.1.13.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
590
- claude_mpm-4.1.13.dist-info/RECORD,,
585
+ claude_mpm-4.1.14.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
586
+ claude_mpm-4.1.14.dist-info/METADATA,sha256=zKwH7YdmTVCBMXRnV5qY9iD5_PN660U4C9_DRFlhO9M,13419
587
+ claude_mpm-4.1.14.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
588
+ claude_mpm-4.1.14.dist-info/entry_points.txt,sha256=FDPZgz8JOvD-6iuXY2l9Zbo9zYVRuE4uz4Qr0vLeGOk,471
589
+ claude_mpm-4.1.14.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
590
+ claude_mpm-4.1.14.dist-info/RECORD,,