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,396 @@
1
+ /**
2
+ * DOM Helper Utilities
3
+ *
4
+ * Common DOM manipulation utilities for dashboard components.
5
+ * Provides safe, consistent methods for element creation and manipulation.
6
+ *
7
+ * @module dom-helpers
8
+ */
9
+
10
+ const domHelpers = {
11
+ /**
12
+ * Create an element with attributes and content
13
+ * @param {string} tag - Element tag name
14
+ * @param {Object} attrs - Attributes to set
15
+ * @param {string|Element|Array} content - Element content
16
+ * @returns {HTMLElement} Created element
17
+ */
18
+ createElement(tag, attrs = {}, content = null) {
19
+ const element = document.createElement(tag);
20
+
21
+ // Set attributes
22
+ for (const [key, value] of Object.entries(attrs)) {
23
+ if (key === 'className') {
24
+ element.className = value;
25
+ } else if (key === 'style' && typeof value === 'object') {
26
+ Object.assign(element.style, value);
27
+ } else if (key === 'dataset' && typeof value === 'object') {
28
+ for (const [dataKey, dataValue] of Object.entries(value)) {
29
+ element.dataset[dataKey] = dataValue;
30
+ }
31
+ } else if (key.startsWith('on') && typeof value === 'function') {
32
+ const eventName = key.slice(2).toLowerCase();
33
+ element.addEventListener(eventName, value);
34
+ } else {
35
+ element.setAttribute(key, value);
36
+ }
37
+ }
38
+
39
+ // Add content
40
+ if (content !== null) {
41
+ this.setContent(element, content);
42
+ }
43
+
44
+ return element;
45
+ },
46
+
47
+ /**
48
+ * Set element content (supports text, HTML, elements, and arrays)
49
+ * @param {HTMLElement} element - Target element
50
+ * @param {string|Element|Array} content - Content to set
51
+ */
52
+ setContent(element, content) {
53
+ if (typeof content === 'string') {
54
+ element.textContent = content;
55
+ } else if (content instanceof HTMLElement) {
56
+ element.appendChild(content);
57
+ } else if (Array.isArray(content)) {
58
+ content.forEach(item => {
59
+ if (typeof item === 'string') {
60
+ element.appendChild(document.createTextNode(item));
61
+ } else if (item instanceof HTMLElement) {
62
+ element.appendChild(item);
63
+ }
64
+ });
65
+ }
66
+ },
67
+
68
+ /**
69
+ * Safely query selector with null check
70
+ * @param {string} selector - CSS selector
71
+ * @param {Element} context - Context element (default: document)
72
+ * @returns {Element|null} Found element or null
73
+ */
74
+ query(selector, context = document) {
75
+ try {
76
+ return context.querySelector(selector);
77
+ } catch (e) {
78
+ console.error(`Invalid selector: ${selector}`, e);
79
+ return null;
80
+ }
81
+ },
82
+
83
+ /**
84
+ * Safely query all matching elements
85
+ * @param {string} selector - CSS selector
86
+ * @param {Element} context - Context element (default: document)
87
+ * @returns {Array} Array of elements
88
+ */
89
+ queryAll(selector, context = document) {
90
+ try {
91
+ return Array.from(context.querySelectorAll(selector));
92
+ } catch (e) {
93
+ console.error(`Invalid selector: ${selector}`, e);
94
+ return [];
95
+ }
96
+ },
97
+
98
+ /**
99
+ * Add classes to element
100
+ * @param {HTMLElement} element - Target element
101
+ * @param {...string} classes - Classes to add
102
+ */
103
+ addClass(element, ...classes) {
104
+ if (element && element.classList) {
105
+ element.classList.add(...classes.filter(c => c));
106
+ }
107
+ },
108
+
109
+ /**
110
+ * Remove classes from element
111
+ * @param {HTMLElement} element - Target element
112
+ * @param {...string} classes - Classes to remove
113
+ */
114
+ removeClass(element, ...classes) {
115
+ if (element && element.classList) {
116
+ element.classList.remove(...classes);
117
+ }
118
+ },
119
+
120
+ /**
121
+ * Toggle classes on element
122
+ * @param {HTMLElement} element - Target element
123
+ * @param {string} className - Class to toggle
124
+ * @param {boolean} force - Force add (true) or remove (false)
125
+ * @returns {boolean} Whether class is now present
126
+ */
127
+ toggleClass(element, className, force) {
128
+ if (element && element.classList) {
129
+ return element.classList.toggle(className, force);
130
+ }
131
+ return false;
132
+ },
133
+
134
+ /**
135
+ * Check if element has class
136
+ * @param {HTMLElement} element - Target element
137
+ * @param {string} className - Class to check
138
+ * @returns {boolean} Whether element has class
139
+ */
140
+ hasClass(element, className) {
141
+ return element && element.classList && element.classList.contains(className);
142
+ },
143
+
144
+ /**
145
+ * Set multiple styles on element
146
+ * @param {HTMLElement} element - Target element
147
+ * @param {Object} styles - Style properties and values
148
+ */
149
+ setStyles(element, styles) {
150
+ if (element && element.style && styles) {
151
+ Object.assign(element.style, styles);
152
+ }
153
+ },
154
+
155
+ /**
156
+ * Get computed style value
157
+ * @param {HTMLElement} element - Target element
158
+ * @param {string} property - CSS property name
159
+ * @returns {string} Computed style value
160
+ */
161
+ getStyle(element, property) {
162
+ if (element) {
163
+ return window.getComputedStyle(element).getPropertyValue(property);
164
+ }
165
+ return '';
166
+ },
167
+
168
+ /**
169
+ * Show element (removes display: none)
170
+ * @param {HTMLElement} element - Element to show
171
+ * @param {string} displayValue - Display value to use (default: '')
172
+ */
173
+ show(element, displayValue = '') {
174
+ if (element && element.style) {
175
+ element.style.display = displayValue;
176
+ }
177
+ },
178
+
179
+ /**
180
+ * Hide element (sets display: none)
181
+ * @param {HTMLElement} element - Element to hide
182
+ */
183
+ hide(element) {
184
+ if (element && element.style) {
185
+ element.style.display = 'none';
186
+ }
187
+ },
188
+
189
+ /**
190
+ * Toggle element visibility
191
+ * @param {HTMLElement} element - Element to toggle
192
+ * @param {boolean} show - Force show (true) or hide (false)
193
+ */
194
+ toggle(element, show) {
195
+ if (element) {
196
+ if (show === undefined) {
197
+ show = element.style.display === 'none';
198
+ }
199
+ if (show) {
200
+ this.show(element);
201
+ } else {
202
+ this.hide(element);
203
+ }
204
+ }
205
+ },
206
+
207
+ /**
208
+ * Remove element from DOM
209
+ * @param {HTMLElement} element - Element to remove
210
+ */
211
+ remove(element) {
212
+ if (element && element.parentNode) {
213
+ element.parentNode.removeChild(element);
214
+ }
215
+ },
216
+
217
+ /**
218
+ * Empty element content
219
+ * @param {HTMLElement} element - Element to empty
220
+ */
221
+ empty(element) {
222
+ if (element) {
223
+ while (element.firstChild) {
224
+ element.removeChild(element.firstChild);
225
+ }
226
+ }
227
+ },
228
+
229
+ /**
230
+ * Insert element after reference element
231
+ * @param {HTMLElement} newElement - Element to insert
232
+ * @param {HTMLElement} referenceElement - Reference element
233
+ */
234
+ insertAfter(newElement, referenceElement) {
235
+ if (referenceElement && referenceElement.parentNode) {
236
+ referenceElement.parentNode.insertBefore(newElement, referenceElement.nextSibling);
237
+ }
238
+ },
239
+
240
+ /**
241
+ * Wrap element with wrapper element
242
+ * @param {HTMLElement} element - Element to wrap
243
+ * @param {HTMLElement} wrapper - Wrapper element
244
+ */
245
+ wrap(element, wrapper) {
246
+ if (element && element.parentNode) {
247
+ element.parentNode.insertBefore(wrapper, element);
248
+ wrapper.appendChild(element);
249
+ }
250
+ },
251
+
252
+ /**
253
+ * Get element dimensions
254
+ * @param {HTMLElement} element - Target element
255
+ * @returns {Object} Width and height
256
+ */
257
+ getDimensions(element) {
258
+ if (element) {
259
+ return {
260
+ width: element.offsetWidth,
261
+ height: element.offsetHeight,
262
+ innerWidth: element.clientWidth,
263
+ innerHeight: element.clientHeight
264
+ };
265
+ }
266
+ return { width: 0, height: 0, innerWidth: 0, innerHeight: 0 };
267
+ },
268
+
269
+ /**
270
+ * Get element position relative to viewport
271
+ * @param {HTMLElement} element - Target element
272
+ * @returns {Object} Position coordinates
273
+ */
274
+ getPosition(element) {
275
+ if (element) {
276
+ const rect = element.getBoundingClientRect();
277
+ return {
278
+ top: rect.top,
279
+ right: rect.right,
280
+ bottom: rect.bottom,
281
+ left: rect.left,
282
+ x: rect.x,
283
+ y: rect.y,
284
+ width: rect.width,
285
+ height: rect.height
286
+ };
287
+ }
288
+ return { top: 0, right: 0, bottom: 0, left: 0, x: 0, y: 0, width: 0, height: 0 };
289
+ },
290
+
291
+ /**
292
+ * Check if element is visible in viewport
293
+ * @param {HTMLElement} element - Element to check
294
+ * @param {boolean} partial - Allow partial visibility
295
+ * @returns {boolean} Whether element is visible
296
+ */
297
+ isInViewport(element, partial = false) {
298
+ if (!element) return false;
299
+
300
+ const rect = element.getBoundingClientRect();
301
+ const windowHeight = window.innerHeight || document.documentElement.clientHeight;
302
+ const windowWidth = window.innerWidth || document.documentElement.clientWidth;
303
+
304
+ const vertInView = partial
305
+ ? rect.top < windowHeight && rect.bottom > 0
306
+ : rect.top >= 0 && rect.bottom <= windowHeight;
307
+
308
+ const horInView = partial
309
+ ? rect.left < windowWidth && rect.right > 0
310
+ : rect.left >= 0 && rect.right <= windowWidth;
311
+
312
+ return vertInView && horInView;
313
+ },
314
+
315
+ /**
316
+ * Smoothly scroll element into view
317
+ * @param {HTMLElement} element - Element to scroll to
318
+ * @param {Object} options - Scroll options
319
+ */
320
+ scrollIntoView(element, options = {}) {
321
+ if (element && element.scrollIntoView) {
322
+ const defaultOptions = {
323
+ behavior: 'smooth',
324
+ block: 'nearest',
325
+ inline: 'nearest'
326
+ };
327
+ element.scrollIntoView({ ...defaultOptions, ...options });
328
+ }
329
+ },
330
+
331
+ /**
332
+ * Create DocumentFragment from HTML string
333
+ * @param {string} html - HTML string
334
+ * @returns {DocumentFragment} Document fragment
335
+ */
336
+ createFragment(html) {
337
+ const template = document.createElement('template');
338
+ template.innerHTML = html.trim();
339
+ return template.content;
340
+ },
341
+
342
+ /**
343
+ * Escape HTML special characters
344
+ * @param {string} text - Text to escape
345
+ * @returns {string} Escaped text
346
+ */
347
+ escapeHtml(text) {
348
+ const div = document.createElement('div');
349
+ div.textContent = text;
350
+ return div.innerHTML;
351
+ },
352
+
353
+ /**
354
+ * Debounce function calls
355
+ * @param {Function} func - Function to debounce
356
+ * @param {number} wait - Wait time in ms
357
+ * @returns {Function} Debounced function
358
+ */
359
+ debounce(func, wait) {
360
+ let timeout;
361
+ return function executedFunction(...args) {
362
+ const later = () => {
363
+ clearTimeout(timeout);
364
+ func(...args);
365
+ };
366
+ clearTimeout(timeout);
367
+ timeout = setTimeout(later, wait);
368
+ };
369
+ },
370
+
371
+ /**
372
+ * Throttle function calls
373
+ * @param {Function} func - Function to throttle
374
+ * @param {number} limit - Time limit in ms
375
+ * @returns {Function} Throttled function
376
+ */
377
+ throttle(func, limit) {
378
+ let inThrottle;
379
+ return function(...args) {
380
+ if (!inThrottle) {
381
+ func.apply(this, args);
382
+ inThrottle = true;
383
+ setTimeout(() => inThrottle = false, limit);
384
+ }
385
+ };
386
+ }
387
+ };
388
+
389
+ // Support both module and global usage
390
+ if (typeof module !== 'undefined' && module.exports) {
391
+ module.exports = domHelpers;
392
+ } else if (typeof define === 'function' && define.amd) {
393
+ define([], () => domHelpers);
394
+ } else {
395
+ window.domHelpers = domHelpers;
396
+ }