x-ipe 1.0.23__py3-none-any.whl → 1.0.25__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 (146) hide show
  1. x_ipe/app.py +32 -1
  2. x_ipe/handlers/terminal_handlers.py +6 -0
  3. x_ipe/handlers/voice_handlers.py +5 -0
  4. x_ipe/resources/copilot-instructions.md +19 -6
  5. x_ipe/resources/skills/lesson-learned/SKILL.md +208 -0
  6. x_ipe/resources/skills/lesson-learned/references/examples.md +238 -0
  7. x_ipe/resources/skills/project-quality-board-management/SKILL.md +135 -298
  8. x_ipe/resources/skills/project-quality-board-management/references/evaluation-principles.md +213 -0
  9. x_ipe/resources/skills/project-quality-board-management/references/evaluation-procedures.md +214 -0
  10. x_ipe/resources/skills/project-quality-board-management/templates/quality-report.md +70 -18
  11. x_ipe/resources/skills/task-execution-guideline/SKILL.md +2 -2
  12. x_ipe/resources/skills/task-execution-guideline/templates/task-record.yaml +1 -1
  13. x_ipe/resources/skills/task-type-code-implementation/SKILL.md +72 -270
  14. x_ipe/resources/skills/task-type-code-implementation/references/implementation-guidelines.md +432 -0
  15. x_ipe/resources/skills/task-type-code-refactor-v2/SKILL.md +127 -353
  16. x_ipe/resources/skills/task-type-code-refactor-v2/references/refactoring-techniques.md +373 -0
  17. x_ipe/resources/skills/task-type-feature-breakdown/SKILL.md +31 -243
  18. x_ipe/resources/skills/task-type-feature-breakdown/references/breakdown-guidelines.md +330 -0
  19. x_ipe/resources/skills/task-type-feature-refinement/SKILL.md +27 -180
  20. x_ipe/resources/skills/task-type-feature-refinement/references/specification-writing-guide.md +267 -0
  21. x_ipe/resources/skills/task-type-idea-mockup/SKILL.md +38 -276
  22. x_ipe/resources/skills/task-type-idea-mockup/references/mockup-guidelines.md +299 -0
  23. x_ipe/resources/skills/task-type-idea-to-architecture/SKILL.md +20 -218
  24. x_ipe/resources/skills/task-type-idea-to-architecture/references/architecture-patterns.md +342 -0
  25. x_ipe/resources/skills/task-type-ideation/SKILL.md +10 -266
  26. x_ipe/resources/skills/task-type-ideation/references/folder-naming-guide.md +55 -0
  27. x_ipe/resources/skills/task-type-ideation/references/tool-usage-guide.md +236 -0
  28. x_ipe/resources/skills/task-type-ideation-v2/SKILL.md +488 -0
  29. x_ipe/resources/skills/task-type-ideation-v2/references/examples.md +377 -0
  30. x_ipe/resources/skills/task-type-ideation-v2/references/folder-naming-guide.md +74 -0
  31. x_ipe/resources/skills/task-type-ideation-v2/references/tool-usage-guide.md +145 -0
  32. x_ipe/resources/skills/task-type-ideation-v2/references/visualization-guide.md +160 -0
  33. x_ipe/resources/skills/task-type-ideation-v2/templates/idea-summary.md +86 -0
  34. x_ipe/resources/skills/task-type-refactoring-analysis/SKILL.md +83 -145
  35. x_ipe/resources/skills/task-type-refactoring-analysis/references/output-schema.md +172 -0
  36. x_ipe/resources/skills/task-type-technical-design/SKILL.md +28 -214
  37. x_ipe/resources/skills/task-type-technical-design/references/design-templates.md +422 -0
  38. x_ipe/resources/skills/task-type-test-generation/SKILL.md +47 -332
  39. x_ipe/resources/skills/task-type-test-generation/references/test-patterns.md +368 -0
  40. x_ipe/resources/skills/tool-tracing-creator/SKILL.md +312 -0
  41. x_ipe/resources/skills/tool-tracing-creator/references/examples.md +324 -0
  42. x_ipe/resources/skills/tool-tracing-instrumentation/SKILL.md +373 -0
  43. x_ipe/resources/skills/tool-tracing-instrumentation/references/examples.md +264 -0
  44. x_ipe/resources/skills/x-ipe-skill-creator-v3/SKILL.md +486 -0
  45. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/10. example-gate-conditions.md +73 -0
  46. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/11. reference-quality-standards.md +127 -0
  47. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/2. reference-section-order.md +127 -0
  48. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/3. example-step-based-code-review.md +84 -0
  49. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/4. example-step-based-feature-implementation.md +113 -0
  50. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/5. example-function-based-validation.md +73 -0
  51. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/6. example-function-based-analysis.md +94 -0
  52. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/7. example-task-io-code-implementation.md +36 -0
  53. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/8. example-structured-summary.md +43 -0
  54. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/9. example-dor-dod.md +77 -0
  55. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/examples.md +429 -0
  56. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/skill-general-guidelines-v2.md +611 -0
  57. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-meta.md +153 -0
  58. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-task-based.md +324 -0
  59. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-task-category.md +109 -0
  60. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-tool.md +205 -0
  61. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-meta.md +334 -0
  62. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-task-based.md +279 -0
  63. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-tool.md +175 -0
  64. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-workflow-orchestration.md +329 -0
  65. x_ipe/resources/skills/x-ipe-task-based-ideation/SKILL.md +487 -0
  66. x_ipe/resources/skills/x-ipe-task-based-ideation/references/examples.md +377 -0
  67. x_ipe/resources/skills/x-ipe-task-based-ideation/references/folder-naming-guide.md +74 -0
  68. x_ipe/resources/skills/x-ipe-task-based-ideation/references/tool-usage-guide.md +145 -0
  69. x_ipe/resources/skills/x-ipe-task-based-ideation/references/visualization-guide.md +160 -0
  70. x_ipe/resources/skills/x-ipe-task-based-ideation/templates/idea-summary.md +86 -0
  71. x_ipe/routes/__init__.py +2 -0
  72. x_ipe/routes/ideas_routes.py +289 -0
  73. x_ipe/routes/kb_routes.py +80 -0
  74. x_ipe/routes/main_routes.py +18 -0
  75. x_ipe/routes/project_routes.py +7 -0
  76. x_ipe/routes/proxy_routes.py +10 -2
  77. x_ipe/routes/quality_evaluation_routes.py +193 -0
  78. x_ipe/routes/settings_routes.py +6 -0
  79. x_ipe/routes/tools_routes.py +6 -0
  80. x_ipe/routes/tracing_routes.py +232 -0
  81. x_ipe/routes/uiux_feedback_routes.py +50 -0
  82. x_ipe/services/__init__.py +5 -0
  83. x_ipe/services/config_service.py +6 -0
  84. x_ipe/services/file_service.py +20 -0
  85. x_ipe/services/homepage_service.py +160 -0
  86. x_ipe/services/ideas_service.py +535 -2
  87. x_ipe/services/kb_service.py +378 -0
  88. x_ipe/services/proxy_service.py +37 -7
  89. x_ipe/services/settings_service.py +13 -0
  90. x_ipe/services/skills_service.py +4 -0
  91. x_ipe/services/terminal_service.py +24 -0
  92. x_ipe/services/themes_service.py +4 -0
  93. x_ipe/services/tools_config_service.py +4 -0
  94. x_ipe/services/tracing_service.py +333 -0
  95. x_ipe/services/uiux_feedback_service.py +148 -1
  96. x_ipe/services/voice_input_service_v2.py +11 -0
  97. x_ipe/static/css/base.css +7 -0
  98. x_ipe/static/css/homepage-infinity.css +330 -0
  99. x_ipe/static/css/kb-core.css +301 -0
  100. x_ipe/static/css/quality-evaluation.css +345 -0
  101. x_ipe/static/css/sidebar.css +14 -4
  102. x_ipe/static/css/terminal.css +23 -0
  103. x_ipe/static/css/tracing-dashboard.css +796 -0
  104. x_ipe/static/css/uiux-feedback.css +7 -1
  105. x_ipe/static/css/workplace.css +636 -0
  106. x_ipe/static/img/homepage-infinity-loop.png +0 -0
  107. x_ipe/static/js/features/confirm-dialog.js +169 -0
  108. x_ipe/static/js/features/folder-view.js +742 -0
  109. x_ipe/static/js/features/homepage-infinity.js +314 -0
  110. x_ipe/static/js/features/kb-core.js +371 -0
  111. x_ipe/static/js/features/quality-evaluation.js +387 -0
  112. x_ipe/static/js/features/sidebar.js +255 -12
  113. x_ipe/static/js/features/tracing-dashboard.js +855 -0
  114. x_ipe/static/js/features/tracing-graph.js +1031 -0
  115. x_ipe/static/js/features/tree-drag.js +227 -0
  116. x_ipe/static/js/features/tree-search.js +228 -0
  117. x_ipe/static/js/features/workplace.js +661 -33
  118. x_ipe/static/js/init.js +76 -0
  119. x_ipe/static/js/terminal-v2.js +45 -14
  120. x_ipe/static/js/terminal.js +50 -49
  121. x_ipe/static/js/uiux-feedback.js +75 -16
  122. x_ipe/templates/base.html +24 -0
  123. x_ipe/templates/index.html +10 -1
  124. x_ipe/templates/knowledge-base.html +110 -0
  125. x_ipe/templates/workplace.html +4 -0
  126. x_ipe/tracing/__init__.py +37 -0
  127. x_ipe/tracing/buffer.py +135 -0
  128. x_ipe/tracing/context.py +125 -0
  129. x_ipe/tracing/decorator.py +288 -0
  130. x_ipe/tracing/middleware.py +197 -0
  131. x_ipe/tracing/parser.py +235 -0
  132. x_ipe/tracing/redactor.py +111 -0
  133. x_ipe/tracing/writer.py +122 -0
  134. {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/METADATA +2 -2
  135. {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/RECORD +138 -65
  136. x_ipe/app.py.bak +0 -1333
  137. x_ipe/resources/skills/x-ipe-skill-creator/SKILL.md +0 -329
  138. x_ipe/resources/skills/x-ipe-skill-creator/references/output-patterns.md +0 -169
  139. x_ipe/resources/skills/x-ipe-skill-creator/references/skill-structure.md +0 -162
  140. x_ipe/resources/skills/x-ipe-skill-creator/references/workflows.md +0 -110
  141. x_ipe/resources/skills/x-ipe-skill-creator/templates/references/examples.md +0 -113
  142. x_ipe/resources/skills/x-ipe-skill-creator/templates/skill-category-skill.md +0 -296
  143. x_ipe/resources/skills/x-ipe-skill-creator/templates/task-type-skill.md +0 -269
  144. {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/WHEEL +0 -0
  145. {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/entry_points.txt +0 -0
  146. {x_ipe-1.0.23.dist-info → x_ipe-1.0.25.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,227 @@
1
+ /**
2
+ * TreeDragManager - Drag-drop file/folder reorganization
3
+ * FEATURE-008 CR-006: Folder Tree UX Enhancement
4
+ *
5
+ * Provides:
6
+ * - Drag-and-drop to move files/folders
7
+ * - Visual feedback (dragging state, valid/invalid targets)
8
+ * - Validation (prevent drop into self/children)
9
+ * - API integration for move operations
10
+ */
11
+ class TreeDragManager {
12
+ constructor(options) {
13
+ this.treeContainer = options.treeContainer;
14
+ this.onMove = options.onMove; // Callback: async (sourcePath, targetPath) => boolean
15
+ this.onMoveComplete = options.onMoveComplete || null; // Called after successful move
16
+ this.draggedItem = null;
17
+ this.draggedPath = null;
18
+ this.draggedType = null;
19
+ }
20
+
21
+ /**
22
+ * Initialize drag-drop functionality
23
+ */
24
+ init() {
25
+ this._bindEvents();
26
+ }
27
+
28
+ /**
29
+ * Bind drag-drop event listeners using event delegation
30
+ */
31
+ _bindEvents() {
32
+ // Use event delegation on tree container
33
+ this.treeContainer.addEventListener('dragstart', this._onDragStart.bind(this));
34
+ this.treeContainer.addEventListener('dragend', this._onDragEnd.bind(this));
35
+ this.treeContainer.addEventListener('dragover', this._onDragOver.bind(this));
36
+ this.treeContainer.addEventListener('dragleave', this._onDragLeave.bind(this));
37
+ this.treeContainer.addEventListener('drop', this._onDrop.bind(this));
38
+ }
39
+
40
+ /**
41
+ * Make an item draggable
42
+ * @param {HTMLElement} item - Tree item element
43
+ */
44
+ enableDrag(item) {
45
+ item.setAttribute('draggable', 'true');
46
+ item.dataset.draggable = 'true';
47
+ }
48
+
49
+ /**
50
+ * Handle drag start
51
+ */
52
+ _onDragStart(e) {
53
+ const item = e.target.closest('.tree-item[data-draggable="true"]');
54
+ if (!item) return;
55
+
56
+ this.draggedItem = item;
57
+ this.draggedPath = item.dataset.path;
58
+ this.draggedType = item.dataset.type;
59
+
60
+ // Set drag data
61
+ e.dataTransfer.effectAllowed = 'move';
62
+ e.dataTransfer.setData('text/plain', this.draggedPath);
63
+
64
+ // Add dragging class after a small delay (to allow drag image to be captured)
65
+ setTimeout(() => {
66
+ item.classList.add('dragging');
67
+ }, 0);
68
+ }
69
+
70
+ /**
71
+ * Handle drag end
72
+ */
73
+ _onDragEnd(e) {
74
+ if (this.draggedItem) {
75
+ this.draggedItem.classList.remove('dragging');
76
+ }
77
+
78
+ // Clear all drag states
79
+ this.treeContainer.querySelectorAll('.drag-over, .drag-invalid').forEach(el => {
80
+ el.classList.remove('drag-over', 'drag-invalid');
81
+ });
82
+
83
+ this.draggedItem = null;
84
+ this.draggedPath = null;
85
+ this.draggedType = null;
86
+ }
87
+
88
+ /**
89
+ * Handle drag over
90
+ */
91
+ _onDragOver(e) {
92
+ e.preventDefault();
93
+
94
+ if (!this.draggedItem) return;
95
+
96
+ const target = e.target.closest('.tree-item[data-type="folder"]');
97
+ if (!target || target === this.draggedItem) {
98
+ e.dataTransfer.dropEffect = 'none';
99
+ return;
100
+ }
101
+
102
+ const targetPath = target.dataset.path;
103
+
104
+ if (this._isValidDrop(targetPath)) {
105
+ e.dataTransfer.dropEffect = 'move';
106
+ target.classList.add('drag-over');
107
+ target.classList.remove('drag-invalid');
108
+ } else {
109
+ e.dataTransfer.dropEffect = 'none';
110
+ target.classList.add('drag-invalid');
111
+ target.classList.remove('drag-over');
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Handle drag leave
117
+ */
118
+ _onDragLeave(e) {
119
+ const target = e.target.closest('.tree-item');
120
+ if (target) {
121
+ // Only remove if we're actually leaving (not entering a child)
122
+ const relatedTarget = e.relatedTarget;
123
+ if (!target.contains(relatedTarget)) {
124
+ target.classList.remove('drag-over', 'drag-invalid');
125
+ }
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Handle drop
131
+ */
132
+ async _onDrop(e) {
133
+ e.preventDefault();
134
+
135
+ const target = e.target.closest('.tree-item[data-type="folder"]');
136
+
137
+ if (!target || !this.draggedItem) {
138
+ return;
139
+ }
140
+
141
+ const targetPath = target.dataset.path;
142
+
143
+ // Clear visual states
144
+ target.classList.remove('drag-over', 'drag-invalid');
145
+
146
+ if (!this._isValidDrop(targetPath)) {
147
+ this._showInvalidFeedback(target);
148
+ return;
149
+ }
150
+
151
+ // Perform the move
152
+ const sourcePath = this.draggedPath;
153
+
154
+ try {
155
+ // Show loading state
156
+ this.draggedItem.classList.add('moving');
157
+
158
+ if (this.onMove) {
159
+ const success = await this.onMove(sourcePath, targetPath);
160
+
161
+ if (success && this.onMoveComplete) {
162
+ this.onMoveComplete(sourcePath, targetPath);
163
+ }
164
+ }
165
+ } catch (error) {
166
+ console.error('Move failed:', error);
167
+ this._showInvalidFeedback(this.draggedItem);
168
+ } finally {
169
+ if (this.draggedItem) {
170
+ this.draggedItem.classList.remove('moving');
171
+ }
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Check if drop is valid
177
+ * @param {string} targetPath - Target folder path
178
+ * @returns {boolean}
179
+ */
180
+ _isValidDrop(targetPath) {
181
+ if (!this.draggedPath) return false;
182
+
183
+ // Cannot drop onto self
184
+ if (this.draggedPath === targetPath) return false;
185
+
186
+ // Cannot drop folder into its own child
187
+ if (this.draggedType === 'folder') {
188
+ if (targetPath.startsWith(this.draggedPath + '/')) {
189
+ return false;
190
+ }
191
+ }
192
+
193
+ return true;
194
+ }
195
+
196
+ /**
197
+ * Show invalid drop feedback (shake animation)
198
+ * @param {HTMLElement} target - Target element
199
+ */
200
+ _showInvalidFeedback(target) {
201
+ if (!target) return;
202
+
203
+ target.classList.add('drag-invalid');
204
+ target.style.animation = 'shake 0.3s ease';
205
+
206
+ setTimeout(() => {
207
+ target.classList.remove('drag-invalid');
208
+ target.style.animation = '';
209
+ }, 300);
210
+ }
211
+
212
+ /**
213
+ * Destroy the drag manager
214
+ */
215
+ destroy() {
216
+ this.treeContainer.removeEventListener('dragstart', this._onDragStart);
217
+ this.treeContainer.removeEventListener('dragend', this._onDragEnd);
218
+ this.treeContainer.removeEventListener('dragover', this._onDragOver);
219
+ this.treeContainer.removeEventListener('dragleave', this._onDragLeave);
220
+ this.treeContainer.removeEventListener('drop', this._onDrop);
221
+ }
222
+ }
223
+
224
+ // Export for module usage
225
+ if (typeof module !== 'undefined' && module.exports) {
226
+ module.exports = TreeDragManager;
227
+ }
@@ -0,0 +1,228 @@
1
+ /**
2
+ * TreeSearchManager - Search/filter tree functionality
3
+ * FEATURE-008 CR-006: Folder Tree UX Enhancement
4
+ *
5
+ * Provides:
6
+ * - Search bar in tree header
7
+ * - Real-time filtering with debounce
8
+ * - Preserves parent folder context for matches
9
+ * - Clear button and keyboard shortcuts
10
+ */
11
+ class TreeSearchManager {
12
+ constructor(options) {
13
+ this.treeContainer = options.treeContainer;
14
+ this.onSearch = options.onSearch || null; // Optional callback for API-based search
15
+ this.searchInput = null;
16
+ this.clearBtn = null;
17
+ this.debounceTimer = null;
18
+ this.debounceDelay = 150;
19
+ }
20
+
21
+ /**
22
+ * Initialize search functionality
23
+ */
24
+ init() {
25
+ this._createSearchBar();
26
+ this._bindEvents();
27
+ }
28
+
29
+ /**
30
+ * Create the search bar UI
31
+ */
32
+ _createSearchBar() {
33
+ const header = this.treeContainer.closest('.workplace-sidebar-content')
34
+ ?.querySelector('.workplace-sidebar-header');
35
+
36
+ if (!header) {
37
+ console.warn('TreeSearchManager: Could not find sidebar header');
38
+ return;
39
+ }
40
+
41
+ // Check if search bar already exists
42
+ if (header.parentElement.querySelector('.tree-search-container')) {
43
+ this.searchInput = header.parentElement.querySelector('.tree-search-input');
44
+ this.clearBtn = header.parentElement.querySelector('.tree-search-clear');
45
+ return;
46
+ }
47
+
48
+ const searchHtml = `
49
+ <div class="tree-search-container">
50
+ <div class="tree-search-wrapper">
51
+ <i class="bi bi-search tree-search-icon"></i>
52
+ <input type="text"
53
+ class="tree-search-input"
54
+ placeholder="Filter files and folders..."
55
+ aria-label="Search files and folders">
56
+ <button class="tree-search-clear"
57
+ type="button"
58
+ title="Clear search"
59
+ style="display: none;">
60
+ <i class="bi bi-x-lg"></i>
61
+ </button>
62
+ </div>
63
+ </div>
64
+ `;
65
+
66
+ header.insertAdjacentHTML('afterend', searchHtml);
67
+ this.searchInput = header.nextElementSibling.querySelector('.tree-search-input');
68
+ this.clearBtn = header.nextElementSibling.querySelector('.tree-search-clear');
69
+ }
70
+
71
+ /**
72
+ * Bind event listeners
73
+ */
74
+ _bindEvents() {
75
+ if (!this.searchInput) return;
76
+
77
+ // Input handler with debounce
78
+ this.searchInput.addEventListener('input', (e) => {
79
+ const query = e.target.value;
80
+
81
+ // Show/hide clear button
82
+ this.clearBtn.style.display = query ? 'flex' : 'none';
83
+
84
+ // Debounce the filter
85
+ clearTimeout(this.debounceTimer);
86
+ this.debounceTimer = setTimeout(() => {
87
+ this._filterTree(query);
88
+ }, this.debounceDelay);
89
+ });
90
+
91
+ // Clear button handler
92
+ this.clearBtn.addEventListener('click', () => {
93
+ this.clear();
94
+ });
95
+
96
+ // Keyboard shortcuts
97
+ this.searchInput.addEventListener('keydown', (e) => {
98
+ if (e.key === 'Escape') {
99
+ this.clear();
100
+ this.searchInput.blur();
101
+ }
102
+ });
103
+ }
104
+
105
+ /**
106
+ * Filter tree items based on query
107
+ * @param {string} query - Search query
108
+ */
109
+ _filterTree(query) {
110
+ const normalizedQuery = query.toLowerCase().trim();
111
+
112
+ // If callback provided, use API-based search
113
+ if (this.onSearch) {
114
+ this.onSearch(normalizedQuery);
115
+ return;
116
+ }
117
+
118
+ // Client-side filtering
119
+ const items = this.treeContainer.querySelectorAll('.tree-item');
120
+
121
+ if (!normalizedQuery) {
122
+ // Show all items and collapse folders
123
+ items.forEach(item => {
124
+ item.style.display = '';
125
+ item.classList.remove('search-match', 'search-parent', 'expanded');
126
+ const childContainer = item.querySelector('.tree-children');
127
+ if (childContainer) {
128
+ childContainer.style.display = 'none';
129
+ }
130
+ });
131
+ return;
132
+ }
133
+
134
+ // Find matching items and their parent paths
135
+ const matchingPaths = new Set();
136
+ const parentPaths = new Set();
137
+
138
+ items.forEach(item => {
139
+ const label = item.querySelector('.tree-label');
140
+ const name = label?.textContent?.toLowerCase() || '';
141
+ const path = item.dataset.path;
142
+
143
+ if (name.includes(normalizedQuery)) {
144
+ matchingPaths.add(path);
145
+
146
+ // Add all parent paths for context
147
+ if (path) {
148
+ const parts = path.split('/');
149
+ for (let i = 1; i < parts.length; i++) {
150
+ parentPaths.add(parts.slice(0, i).join('/'));
151
+ }
152
+ }
153
+ }
154
+ });
155
+
156
+ // Apply visibility and styling
157
+ items.forEach(item => {
158
+ const path = item.dataset.path;
159
+ const isMatch = matchingPaths.has(path);
160
+ const isParent = parentPaths.has(path);
161
+
162
+ if (isMatch || isParent) {
163
+ item.style.display = '';
164
+ item.classList.toggle('search-match', isMatch);
165
+ item.classList.toggle('search-parent', isParent && !isMatch);
166
+
167
+ // Expand parent folders
168
+ if (isParent) {
169
+ const childContainer = item.querySelector('.tree-children');
170
+ if (childContainer) {
171
+ childContainer.style.display = 'block';
172
+ }
173
+ item.classList.add('expanded');
174
+ }
175
+ } else {
176
+ item.style.display = 'none';
177
+ item.classList.remove('search-match', 'search-parent');
178
+ }
179
+ });
180
+ }
181
+
182
+ /**
183
+ * Clear the search
184
+ */
185
+ clear() {
186
+ if (!this.searchInput) return;
187
+
188
+ this.searchInput.value = '';
189
+ this.clearBtn.style.display = 'none';
190
+ this._filterTree('');
191
+ }
192
+
193
+ /**
194
+ * Get current search query
195
+ * @returns {string}
196
+ */
197
+ getQuery() {
198
+ return this.searchInput?.value || '';
199
+ }
200
+
201
+ /**
202
+ * Set search query programmatically
203
+ * @param {string} query
204
+ */
205
+ setQuery(query) {
206
+ if (!this.searchInput) return;
207
+
208
+ this.searchInput.value = query;
209
+ this.clearBtn.style.display = query ? 'flex' : 'none';
210
+ this._filterTree(query);
211
+ }
212
+
213
+ /**
214
+ * Destroy the search manager
215
+ */
216
+ destroy() {
217
+ clearTimeout(this.debounceTimer);
218
+ const container = this.searchInput?.closest('.tree-search-container');
219
+ if (container) {
220
+ container.remove();
221
+ }
222
+ }
223
+ }
224
+
225
+ // Export for module usage
226
+ if (typeof module !== 'undefined' && module.exports) {
227
+ module.exports = TreeSearchManager;
228
+ }