cursorflow 2.3.2__tar.gz → 2.4.0__tar.gz

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 (51) hide show
  1. {cursorflow-2.3.2 → cursorflow-2.4.0}/MANIFEST.in +2 -0
  2. {cursorflow-2.3.2 → cursorflow-2.4.0}/PKG-INFO +1 -1
  3. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/cli.py +2 -0
  4. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/browser_controller.py +39 -48
  5. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/cursorflow.py +1 -0
  6. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow.egg-info/SOURCES.txt +2 -0
  7. cursorflow-2.4.0/examples/element_inspection_example.py +183 -0
  8. cursorflow-2.4.0/examples/element_measurement_example.py +243 -0
  9. {cursorflow-2.3.2 → cursorflow-2.4.0}/pyproject.toml +2 -2
  10. {cursorflow-2.3.2 → cursorflow-2.4.0}/LICENSE +0 -0
  11. {cursorflow-2.3.2 → cursorflow-2.4.0}/README.md +0 -0
  12. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/__init__.py +0 -0
  13. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/auto_init.py +0 -0
  14. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/auto_updater.py +0 -0
  15. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/action_validator.py +0 -0
  16. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/agent.py +0 -0
  17. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/auth_handler.py +0 -0
  18. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/browser_engine.py +0 -0
  19. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/config_validator.py +0 -0
  20. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/css_iterator.py +0 -0
  21. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/cursor_integration.py +0 -0
  22. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/error_context_collector.py +0 -0
  23. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/error_correlator.py +0 -0
  24. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/event_correlator.py +0 -0
  25. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/file_change_monitor.py +0 -0
  26. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/hmr_detector.py +0 -0
  27. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/log_collector.py +0 -0
  28. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/log_monitor.py +0 -0
  29. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/mockup_comparator.py +0 -0
  30. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/persistent_session.py +0 -0
  31. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/report_generator.py +0 -0
  32. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/core/trace_manager.py +0 -0
  33. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/install_cursorflow_rules.py +0 -0
  34. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/log_sources/local_file.py +0 -0
  35. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/log_sources/ssh_remote.py +0 -0
  36. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/post_install.py +0 -0
  37. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/rules/__init__.py +0 -0
  38. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/rules/cursorflow-installation.mdc +0 -0
  39. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/rules/cursorflow-usage.mdc +0 -0
  40. {cursorflow-2.3.2 → cursorflow-2.4.0}/cursorflow/updater.py +0 -0
  41. {cursorflow-2.3.2 → cursorflow-2.4.0}/docs/user/USAGE_GUIDE.md +0 -0
  42. {cursorflow-2.3.2 → cursorflow-2.4.0}/examples/comprehensive_screenshot_example.py +0 -0
  43. {cursorflow-2.3.2 → cursorflow-2.4.0}/examples/enhanced_screenshot_example.py +0 -0
  44. {cursorflow-2.3.2 → cursorflow-2.4.0}/examples/hot_reload_css_iteration.py +0 -0
  45. {cursorflow-2.3.2 → cursorflow-2.4.0}/examples/mockup_comparison_example.py +0 -0
  46. {cursorflow-2.3.2 → cursorflow-2.4.0}/examples/opensas_example.py +0 -0
  47. {cursorflow-2.3.2 → cursorflow-2.4.0}/examples/react_example.py +0 -0
  48. {cursorflow-2.3.2 → cursorflow-2.4.0}/examples/responsive_testing_example.py +0 -0
  49. {cursorflow-2.3.2 → cursorflow-2.4.0}/examples/v2_comprehensive_demo.py +0 -0
  50. {cursorflow-2.3.2 → cursorflow-2.4.0}/setup.cfg +0 -0
  51. {cursorflow-2.3.2 → cursorflow-2.4.0}/setup.py +0 -0
@@ -19,6 +19,8 @@ include examples/enhanced_screenshot_example.py
19
19
  include examples/responsive_testing_example.py
20
20
  include examples/hot_reload_css_iteration.py
21
21
  include examples/v2_comprehensive_demo.py
22
+ include examples/element_inspection_example.py
23
+ include examples/element_measurement_example.py
22
24
 
23
25
  # INCLUDE: Customer-facing documentation
24
26
  include docs/user/USAGE_GUIDE.md
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cursorflow
3
- Version: 2.3.2
3
+ Version: 2.4.0
4
4
  Summary: 🔥 Complete page intelligence for AI-driven development with Hot Reload Intelligence - captures DOM, network, console, performance, HMR events, and comprehensive page analysis
5
5
  Author-email: GeekWarrior Development <rbush@cooltheory.com>
6
6
  License-Expression: MIT
@@ -801,6 +801,7 @@ def inspect(base_url, path, selector, verbose):
801
801
  )
802
802
 
803
803
  # Comprehensive inspection with full data capture
804
+ # v2.1: Captures ALL visible elements automatically
804
805
  console.print("📸 Capturing comprehensive page data...")
805
806
  results = asyncio.run(flow.execute_and_collect([
806
807
  {"navigate": path},
@@ -996,6 +997,7 @@ def measure(base_url, path, selector, verbose):
996
997
  selectors_list = list(selector)
997
998
 
998
999
  # Execute with screenshot to get comprehensive data
1000
+ # v2.1: Captures ALL visible elements automatically
999
1001
  results = asyncio.run(flow.execute_and_collect([
1000
1002
  {"navigate": path},
1001
1003
  {"wait_for_selector": "body"},
@@ -550,7 +550,7 @@ class BrowserController:
550
550
  }
551
551
 
552
552
  if capture_comprehensive_data:
553
- # Capture comprehensive page analysis
553
+ # Capture comprehensive page analysis (ALL visible elements)
554
554
  comprehensive_data = await self._capture_comprehensive_page_analysis()
555
555
 
556
556
  # Save comprehensive data alongside screenshot
@@ -1122,9 +1122,13 @@ class BrowserController:
1122
1122
  return failed
1123
1123
 
1124
1124
  async def _capture_comprehensive_page_analysis(self) -> Dict[str, Any]:
1125
- """Enhanced comprehensive page analysis with v2.0 features: fonts, animations, resources, storage"""
1125
+ """
1126
+ Enhanced comprehensive page analysis with v2.0 features: fonts, animations, resources, storage
1127
+
1128
+ v2.1: Now captures ALL visible elements - truly comprehensive, no hardcoded limits.
1129
+ """
1126
1130
  try:
1127
- # Capture DOM analysis
1131
+ # Capture DOM analysis (ALL visible elements)
1128
1132
  dom_analysis = await self._capture_dom_analysis()
1129
1133
 
1130
1134
  # Capture current network state
@@ -1684,7 +1688,12 @@ class BrowserController:
1684
1688
  }
1685
1689
 
1686
1690
  async def _capture_dom_analysis(self) -> Dict[str, Any]:
1687
- """Enhanced DOM analysis with multi-selector strategies and accessibility data (v2.0)"""
1691
+ """
1692
+ Enhanced DOM analysis with multi-selector strategies and accessibility data (v2.0)
1693
+
1694
+ Captures ALL visible elements on the page - truly comprehensive analysis.
1695
+ No hardcoded selector limits, no artificial filtering.
1696
+ """
1688
1697
  try:
1689
1698
  dom_analysis = await self.page.evaluate("""
1690
1699
  () => {
@@ -2022,46 +2031,29 @@ class BrowserController:
2022
2031
  };
2023
2032
  }
2024
2033
 
2025
- // Get all significant elements with enhanced analysis
2034
+ // Get ALL visible elements - truly comprehensive analysis
2026
2035
  const elements = [];
2027
- const selectors = [
2028
- // Structural elements
2029
- 'body', 'main', 'header', 'nav', 'aside', 'footer', 'section', 'article',
2030
- // Common containers
2031
- '.container', '.wrapper', '.content', '.sidebar', '.header', '.footer',
2032
- '.navbar', '.nav', '.menu', '.main', '.page', '.app', '.layout',
2033
- // Interactive elements
2034
- 'button', '.btn', '.button', 'a', '.link', 'input', 'form', '.form',
2035
- 'select', 'textarea', '.input', '.field',
2036
- // Content elements
2037
- 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', '.title', '.heading',
2038
- '.text', '.content', '.description',
2039
- // Layout elements
2040
- '.row', '.col', '.column', '.grid', '.flex', '.card', '.panel',
2041
- '.box', '.item', '.component',
2042
- // Common UI components
2043
- '.modal', '.dropdown', '.tooltip', '.alert', '.badge', '.tab',
2044
- '.table', '.list', '.menu-item'
2045
- ];
2046
2036
 
2047
- selectors.forEach(selector => {
2037
+ // Query EVERY element on the page (true comprehensive capture)
2038
+ const allElements = document.querySelectorAll('*');
2039
+
2040
+ allElements.forEach((element, globalIndex) => {
2048
2041
  try {
2049
- document.querySelectorAll(selector).forEach((element, index) => {
2050
- const computedStyles = getComputedStylesDetailed(element);
2051
- const visualContext = getVisualContext(element, computedStyles);
2042
+ const computedStyles = getComputedStylesDetailed(element);
2043
+ const visualContext = getVisualContext(element, computedStyles);
2044
+
2045
+ // Only include elements with meaningful size OR important semantic meaning
2046
+ // This filters out invisible helper elements but keeps everything visible
2047
+ if (visualContext.bounding_box.width > 0 && visualContext.bounding_box.height > 0 ||
2048
+ ['HTML', 'BODY', 'HEAD', 'HEADER', 'NAV', 'MAIN', 'ASIDE', 'FOOTER'].includes(element.tagName)) {
2052
2049
 
2053
- // Only include elements with meaningful size or important semantic meaning
2054
- if (visualContext.bounding_box.width > 0 && visualContext.bounding_box.height > 0 ||
2055
- ['HEADER', 'NAV', 'MAIN', 'ASIDE', 'FOOTER'].includes(element.tagName)) {
2056
-
2057
- elements.push({
2058
- // Basic element info
2059
- selector: selector,
2060
- index: index,
2061
- tagName: element.tagName.toLowerCase(),
2062
- id: element.id || null,
2063
- className: element.className || null,
2064
- textContent: element.textContent ? element.textContent.trim().substring(0, 200) : null,
2050
+ elements.push({
2051
+ // Basic element info
2052
+ index: globalIndex,
2053
+ tagName: element.tagName.toLowerCase(),
2054
+ id: element.id || null,
2055
+ className: element.className || null,
2056
+ textContent: element.textContent ? element.textContent.trim().substring(0, 200) : null,
2065
2057
 
2066
2058
  // v2.0 Enhancement: Multiple selector strategies
2067
2059
  selectors: generateMultipleSelectors(element),
@@ -2084,14 +2076,13 @@ class BrowserController:
2084
2076
  return attrs;
2085
2077
  }, {}),
2086
2078
 
2087
- // Element hierarchy info
2088
- childrenCount: element.children.length,
2089
- parentTagName: element.parentElement ? element.parentElement.tagName.toLowerCase() : null
2090
- });
2091
- }
2092
- });
2079
+ // Element hierarchy info
2080
+ childrenCount: element.children.length,
2081
+ parentTagName: element.parentElement ? element.parentElement.tagName.toLowerCase() : null
2082
+ });
2083
+ }
2093
2084
  } catch (e) {
2094
- console.warn(`Failed to analyze selector ${selector}:`, e);
2085
+ // Skip elements that fail to analyze (e.g., detached nodes, iframes)
2095
2086
  }
2096
2087
  });
2097
2088
 
@@ -2166,7 +2157,7 @@ class BrowserController:
2166
2157
  elements: elements,
2167
2158
  totalElements: elements.length,
2168
2159
  captureTimestamp: Date.now(),
2169
- analysisVersion: "2.0" // v2.0 enhanced analysis
2160
+ analysisVersion: "2.1" // v2.1: Truly comprehensive (ALL elements)
2170
2161
  };
2171
2162
  }
2172
2163
  """)
@@ -736,6 +736,7 @@ class CursorFlow:
736
736
  name = "screenshot"
737
737
  options = None
738
738
 
739
+ # v2.1: No need for additional_selectors - we capture ALL visible elements now
739
740
  screenshot_data = await self.browser.screenshot(name, options)
740
741
  self.artifacts["screenshots"].append(screenshot_data)
741
742
 
@@ -37,6 +37,8 @@ cursorflow/rules/cursorflow-installation.mdc
37
37
  cursorflow/rules/cursorflow-usage.mdc
38
38
  docs/user/USAGE_GUIDE.md
39
39
  examples/comprehensive_screenshot_example.py
40
+ examples/element_inspection_example.py
41
+ examples/element_measurement_example.py
40
42
  examples/enhanced_screenshot_example.py
41
43
  examples/hot_reload_css_iteration.py
42
44
  examples/mockup_comparison_example.py
@@ -0,0 +1,183 @@
1
+ """
2
+ Element Inspection Example
3
+
4
+ This example shows how to use the inspect command for comprehensive CSS debugging
5
+ and element analysis. Perfect for understanding layout issues and computed styles.
6
+ """
7
+
8
+ import asyncio
9
+ import json
10
+ from cursorflow import CursorFlow
11
+
12
+ async def inspect_element_comprehensive():
13
+ """Example: Comprehensive element inspection with full CSS analysis"""
14
+
15
+ print("🔍 Comprehensive Element Inspection Example\n")
16
+
17
+ # Initialize CursorFlow
18
+ flow = CursorFlow(
19
+ base_url="http://localhost:3000",
20
+ log_config={'source': 'local', 'paths': []},
21
+ browser_config={'headless': True}
22
+ )
23
+
24
+ # Execute inspection with screenshot
25
+ print("📸 Inspecting #messages-panel with comprehensive data capture...")
26
+ results = await flow.execute_and_collect([
27
+ {"navigate": "/console"},
28
+ {"wait_for_selector": "body"},
29
+ {"screenshot": "inspection"}
30
+ ])
31
+
32
+ # Extract element data from comprehensive analysis
33
+ comprehensive_data = results.get('comprehensive_data', {})
34
+ dom_analysis = comprehensive_data.get('dom_analysis', {})
35
+ elements = dom_analysis.get('elements', [])
36
+
37
+ # Find the target element
38
+ target_selector = "#messages-panel"
39
+ matching_elements = [
40
+ el for el in elements
41
+ if el.get('id') == 'messages-panel'
42
+ ]
43
+
44
+ if not matching_elements:
45
+ print(f"⚠️ Element {target_selector} not found")
46
+ return
47
+
48
+ element = matching_elements[0]
49
+
50
+ # Display comprehensive element information
51
+ print(f"\n═══ Element: {target_selector} ═══\n")
52
+
53
+ # Basic info
54
+ print(f"Tag: {element.get('tagName', 'unknown')}")
55
+ print(f"ID: #{element.get('id', 'N/A')}")
56
+ print(f"Classes: .{element.get('className', 'N/A')}")
57
+
58
+ # Dimensions
59
+ visual_context = element.get('visual_context', {})
60
+ bbox = visual_context.get('bounding_box', {})
61
+ if bbox:
62
+ print(f"\n📐 Dimensions:")
63
+ print(f" Position: x={bbox.get('x', 0):.0f}, y={bbox.get('y', 0):.0f}")
64
+ print(f" Size: {bbox.get('width', 0):.0f}w × {bbox.get('height', 0):.0f}h")
65
+
66
+ # Computed styles
67
+ computed = element.get('computedStyles', {})
68
+ if computed:
69
+ print(f"\n🎨 Key CSS Properties:")
70
+ print(f" display: {computed.get('display', 'N/A')}")
71
+ print(f" position: {computed.get('position', 'N/A')}")
72
+ print(f" flex: {computed.get('flex', 'N/A')}")
73
+ print(f" width: {computed.get('width', 'N/A')}")
74
+ print(f" height: {computed.get('height', 'N/A')}")
75
+
76
+ # Accessibility
77
+ accessibility = element.get('accessibility', {})
78
+ if accessibility:
79
+ print(f"\n♿ Accessibility:")
80
+ print(f" Role: {accessibility.get('role', 'N/A')}")
81
+ print(f" Interactive: {'✅' if accessibility.get('isInteractive') else '❌'}")
82
+
83
+ # Visual context
84
+ visibility = visual_context.get('visibility', {})
85
+ if visibility:
86
+ print(f"\n👁️ Visual Context:")
87
+ print(f" Visible: {'✅' if visibility.get('is_visible') else '❌'}")
88
+ print(f" In viewport: {'✅' if visibility.get('is_in_viewport') else '❌'}")
89
+
90
+ # Screenshot location
91
+ screenshots = results.get('artifacts', {}).get('screenshots', [])
92
+ if screenshots:
93
+ print(f"\n📸 Screenshot saved: {screenshots[0]}")
94
+
95
+ print("\n✅ Inspection complete!")
96
+
97
+ async def inspect_multiple_elements():
98
+ """Example: Inspect multiple elements for comparison"""
99
+
100
+ print("\n🔍 Multiple Element Inspection Example\n")
101
+
102
+ flow = CursorFlow(
103
+ base_url="http://localhost:3000",
104
+ log_config={'source': 'local', 'paths': []},
105
+ browser_config={'headless': True}
106
+ )
107
+
108
+ # Execute inspection
109
+ results = await flow.execute_and_collect([
110
+ {"navigate": "/dashboard"},
111
+ {"wait_for_selector": "body"},
112
+ {"screenshot": "dashboard"}
113
+ ])
114
+
115
+ # Extract element data
116
+ comprehensive_data = results.get('comprehensive_data', {})
117
+ elements = comprehensive_data.get('dom_analysis', {}).get('elements', [])
118
+
119
+ # Compare multiple panels
120
+ selectors = [".sidebar", ".main-content", ".right-panel"]
121
+
122
+ print("📊 Comparing panel widths:\n")
123
+ for selector in selectors:
124
+ matching = [
125
+ el for el in elements
126
+ if selector[1:] in el.get('className', '').split()
127
+ ]
128
+
129
+ if matching:
130
+ element = matching[0]
131
+ bbox = element.get('visual_context', {}).get('bounding_box', {})
132
+ computed = element.get('computedStyles', {})
133
+
134
+ print(f"{selector}:")
135
+ print(f" Rendered: {bbox.get('width', 0):.0f}px")
136
+ print(f" CSS: {computed.get('width', 'N/A')}")
137
+ print(f" Flex: {computed.get('flex', 'N/A')}\n")
138
+
139
+ async def inspect_with_verbose_css():
140
+ """Example: Get ALL computed CSS properties for deep debugging"""
141
+
142
+ print("\n🔍 Verbose CSS Inspection Example\n")
143
+
144
+ flow = CursorFlow(
145
+ base_url="http://localhost:3000",
146
+ log_config={'source': 'local', 'paths': []},
147
+ browser_config={'headless': True}
148
+ )
149
+
150
+ results = await flow.execute_and_collect([
151
+ {"navigate": "/component"},
152
+ {"wait_for_selector": "body"},
153
+ {"screenshot": "component"}
154
+ ])
155
+
156
+ # Extract element
157
+ elements = results.get('comprehensive_data', {}).get('dom_analysis', {}).get('elements', [])
158
+
159
+ if elements:
160
+ element = elements[0] # First element
161
+ computed = element.get('computedStyles', {})
162
+
163
+ print(f"🎨 All {len(computed)} Computed CSS Properties:\n")
164
+
165
+ for prop, value in sorted(computed.items())[:20]: # Show first 20
166
+ print(f" {prop}: {value}")
167
+
168
+ print(f"\n ... and {len(computed) - 20} more properties")
169
+
170
+ if __name__ == '__main__':
171
+ print("=" * 60)
172
+ print("CursorFlow Element Inspection Examples")
173
+ print("=" * 60)
174
+
175
+ # Run examples
176
+ asyncio.run(inspect_element_comprehensive())
177
+ asyncio.run(inspect_multiple_elements())
178
+ asyncio.run(inspect_with_verbose_css())
179
+
180
+ print("\n" + "=" * 60)
181
+ print("✅ All examples completed!")
182
+ print("=" * 60)
183
+
@@ -0,0 +1,243 @@
1
+ """
2
+ Element Measurement Example
3
+
4
+ This example shows how to use the measure command for surgical dimension checking
5
+ and quick CSS verification. Perfect for validating layout changes.
6
+ """
7
+
8
+ import asyncio
9
+ import json
10
+ from cursorflow import CursorFlow
11
+
12
+ async def measure_single_element():
13
+ """Example: Quick dimension check for a single element"""
14
+
15
+ print("📏 Single Element Measurement Example\n")
16
+
17
+ flow = CursorFlow(
18
+ base_url="http://localhost:3000",
19
+ log_config={'source': 'local', 'paths': []},
20
+ browser_config={'headless': True}
21
+ )
22
+
23
+ # Execute measurement
24
+ print("📐 Measuring #main-panel dimensions...")
25
+ results = await flow.execute_and_collect([
26
+ {"navigate": "/dashboard"},
27
+ {"wait_for_selector": "body"},
28
+ {"screenshot": "measurement"}
29
+ ])
30
+
31
+ # Extract element data
32
+ elements = results.get('comprehensive_data', {}).get('dom_analysis', {}).get('elements', [])
33
+
34
+ # Find target element
35
+ matching = [el for el in elements if el.get('id') == 'main-panel']
36
+
37
+ if not matching:
38
+ print("⚠️ Element #main-panel not found")
39
+ return
40
+
41
+ element = matching[0]
42
+ bbox = element.get('visual_context', {}).get('bounding_box', {})
43
+ computed = element.get('computedStyles', {})
44
+
45
+ # Display measurements (surgical precision)
46
+ print(f"\n#main-panel")
47
+ print(f" 📐 Rendered: {bbox.get('width', 0):.0f}w × {bbox.get('height', 0):.0f}h")
48
+ print(f" 📍 Position: x={bbox.get('x', 0):.0f}, y={bbox.get('y', 0):.0f}")
49
+ print(f" 🎨 Display: {computed.get('display', 'N/A')}")
50
+ print(f" 📦 CSS Width: {computed.get('width', 'N/A')}")
51
+
52
+ if computed.get('flex'):
53
+ print(f" 🔧 Flex: {computed.get('flex')}")
54
+
55
+ print("\n✅ Measurement complete!")
56
+
57
+ async def measure_multiple_elements():
58
+ """Example: Measure multiple elements at once"""
59
+
60
+ print("\n📏 Multiple Element Measurement Example\n")
61
+
62
+ flow = CursorFlow(
63
+ base_url="http://localhost:3000",
64
+ log_config={'source': 'local', 'paths': []},
65
+ browser_config={'headless': True}
66
+ )
67
+
68
+ results = await flow.execute_and_collect([
69
+ {"navigate": "/layout"},
70
+ {"wait_for_selector": "body"},
71
+ {"screenshot": "layout"}
72
+ ])
73
+
74
+ # Extract elements
75
+ elements = results.get('comprehensive_data', {}).get('dom_analysis', {}).get('elements', [])
76
+
77
+ # Measure multiple panels
78
+ selectors = ["#panel1", "#panel2", "#panel3"]
79
+
80
+ print("📊 Measuring layout panels:\n")
81
+
82
+ for selector in selectors:
83
+ matching = [el for el in elements if el.get('id') == selector[1:]]
84
+
85
+ if matching:
86
+ element = matching[0]
87
+ bbox = element.get('visual_context', {}).get('bounding_box', {})
88
+ computed = element.get('computedStyles', {})
89
+
90
+ print(f"{selector}")
91
+ print(f" 📐 Rendered: {bbox.get('width', 0):.0f}w × {bbox.get('height', 0):.0f}h")
92
+ print(f" 📦 CSS Width: {computed.get('width', 'N/A')}")
93
+
94
+ if computed.get('flex'):
95
+ print(f" 🔧 Flex: {computed.get('flex')}")
96
+ if computed.get('flexBasis') != 'auto':
97
+ print(f" 📏 Flex Base: {computed.get('flexBasis')}")
98
+
99
+ print()
100
+
101
+ async def measure_before_and_after():
102
+ """Example: Measure before CSS changes, apply changes, measure after"""
103
+
104
+ print("\n📏 Before/After Measurement Example\n")
105
+
106
+ flow = CursorFlow(
107
+ base_url="http://localhost:3000",
108
+ log_config={'source': 'local', 'paths': []},
109
+ browser_config={'headless': True}
110
+ )
111
+
112
+ # BEFORE measurement
113
+ print("📐 BEFORE CSS changes:")
114
+ before_results = await flow.execute_and_collect([
115
+ {"navigate": "/component"},
116
+ {"wait_for_selector": "body"},
117
+ {"screenshot": "before"}
118
+ ])
119
+
120
+ before_elements = before_results.get('comprehensive_data', {}).get('dom_analysis', {}).get('elements', [])
121
+ before_element = [el for el in before_elements if el.get('id') == 'container'][0]
122
+ before_bbox = before_element.get('visual_context', {}).get('bounding_box', {})
123
+
124
+ print(f" Container: {before_bbox.get('width', 0):.0f}w × {before_bbox.get('height', 0):.0f}h")
125
+
126
+ # --- User would make CSS changes here in actual workflow ---
127
+ print("\n🔧 (Apply CSS changes: .container { padding: 2rem; gap: 1.5rem; })")
128
+ print(" (In real workflow, you'd modify CSS files here)")
129
+
130
+ # AFTER measurement (simulated with new test)
131
+ print("\n📐 AFTER CSS changes:")
132
+ after_results = await flow.execute_and_collect([
133
+ {"navigate": "/component"},
134
+ {"wait_for_selector": "body"},
135
+ {"screenshot": "after"}
136
+ ])
137
+
138
+ after_elements = after_results.get('comprehensive_data', {}).get('dom_analysis', {}).get('elements', [])
139
+ after_element = [el for el in after_elements if el.get('id') == 'container'][0]
140
+ after_bbox = after_element.get('visual_context', {}).get('bounding_box', {})
141
+
142
+ print(f" Container: {after_bbox.get('width', 0):.0f}w × {after_bbox.get('height', 0):.0f}h")
143
+
144
+ # Compare
145
+ width_diff = after_bbox.get('width', 0) - before_bbox.get('width', 0)
146
+ height_diff = after_bbox.get('height', 0) - before_bbox.get('height', 0)
147
+
148
+ print(f"\n📊 Changes:")
149
+ print(f" Width: {'+' if width_diff > 0 else ''}{width_diff:.0f}px")
150
+ print(f" Height: {'+' if height_diff > 0 else ''}{height_diff:.0f}px")
151
+ print("\n✅ CSS changes verified!")
152
+
153
+ async def measure_responsive_breakpoints():
154
+ """Example: Measure element dimensions across responsive breakpoints"""
155
+
156
+ print("\n📏 Responsive Breakpoint Measurement Example\n")
157
+
158
+ viewports = [
159
+ {"width": 375, "height": 667, "name": "mobile"},
160
+ {"width": 768, "height": 1024, "name": "tablet"},
161
+ {"width": 1440, "height": 900, "name": "desktop"}
162
+ ]
163
+
164
+ flow = CursorFlow(
165
+ base_url="http://localhost:3000",
166
+ log_config={'source': 'local', 'paths': []},
167
+ browser_config={'headless': True}
168
+ )
169
+
170
+ print("📱 Measuring across breakpoints:\n")
171
+
172
+ for viewport in viewports:
173
+ # Set viewport size
174
+ flow.browser_config['viewport'] = {"width": viewport['width'], "height": viewport['height']}
175
+
176
+ results = await flow.execute_and_collect([
177
+ {"navigate": "/responsive"},
178
+ {"wait_for_selector": "body"},
179
+ {"screenshot": f"responsive-{viewport['name']}"}
180
+ ])
181
+
182
+ elements = results.get('comprehensive_data', {}).get('dom_analysis', {}).get('elements', [])
183
+ matching = [el for el in elements if el.get('id') == 'main-content']
184
+
185
+ if matching:
186
+ element = matching[0]
187
+ bbox = element.get('visual_context', {}).get('bounding_box', {})
188
+ computed = element.get('computedStyles', {})
189
+
190
+ print(f"{viewport['name'].upper()} ({viewport['width']}x{viewport['height']}):")
191
+ print(f" #main-content: {bbox.get('width', 0):.0f}w × {bbox.get('height', 0):.0f}h")
192
+ print(f" Display: {computed.get('display', 'N/A')}")
193
+ print()
194
+
195
+ async def measure_with_verbose_css():
196
+ """Example: Get all computed CSS for detailed analysis"""
197
+
198
+ print("\n📏 Verbose Measurement (All CSS Properties)\n")
199
+
200
+ flow = CursorFlow(
201
+ base_url="http://localhost:3000",
202
+ log_config={'source': 'local', 'paths': []},
203
+ browser_config={'headless': True}
204
+ )
205
+
206
+ results = await flow.execute_and_collect([
207
+ {"navigate": "/element"},
208
+ {"wait_for_selector": "body"},
209
+ {"screenshot": "element"}
210
+ ])
211
+
212
+ elements = results.get('comprehensive_data', {}).get('dom_analysis', {}).get('elements', [])
213
+
214
+ if elements:
215
+ element = elements[0]
216
+ bbox = element.get('visual_context', {}).get('bounding_box', {})
217
+ computed = element.get('computedStyles', {})
218
+
219
+ print(f"Element: {element.get('tagName', 'unknown')}")
220
+ print(f" 📐 Rendered: {bbox.get('width', 0):.0f}w × {bbox.get('height', 0):.0f}h\n")
221
+ print(f" 🎨 All {len(computed)} Computed CSS Properties:")
222
+
223
+ for prop, value in sorted(computed.items())[:15]:
224
+ print(f" {prop}: {value}")
225
+
226
+ print(f"\n 💡 {len(computed) - 15} more properties available")
227
+
228
+ if __name__ == '__main__':
229
+ print("=" * 60)
230
+ print("CursorFlow Element Measurement Examples")
231
+ print("=" * 60)
232
+
233
+ # Run examples
234
+ asyncio.run(measure_single_element())
235
+ asyncio.run(measure_multiple_elements())
236
+ asyncio.run(measure_before_and_after())
237
+ asyncio.run(measure_responsive_breakpoints())
238
+ asyncio.run(measure_with_verbose_css())
239
+
240
+ print("\n" + "=" * 60)
241
+ print("✅ All examples completed!")
242
+ print("=" * 60)
243
+
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cursorflow"
7
- version = "2.3.2"
7
+ version = "2.4.0"
8
8
  description = "🔥 Complete page intelligence for AI-driven development with Hot Reload Intelligence - captures DOM, network, console, performance, HMR events, and comprehensive page analysis"
9
9
  authors = [
10
10
  {name = "GeekWarrior Development", email = "rbush@cooltheory.com"}
@@ -72,6 +72,6 @@ line-length = 88
72
72
  target-version = ['py38']
73
73
 
74
74
  [tool.mypy]
75
- python_version = "2.3.2"
75
+ python_version = "2.4.0"
76
76
  warn_return_any = true
77
77
  warn_unused_configs = true
File without changes
File without changes
File without changes
File without changes