cursorflow 2.2.9__tar.gz → 2.3.1__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.
- {cursorflow-2.2.9 → cursorflow-2.3.1}/PKG-INFO +19 -1
- {cursorflow-2.2.9 → cursorflow-2.3.1}/README.md +18 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/cli.py +283 -16
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/browser_controller.py +1 -1
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/rules/cursorflow-usage.mdc +50 -1
- {cursorflow-2.2.9 → cursorflow-2.3.1}/docs/user/USAGE_GUIDE.md +132 -2
- {cursorflow-2.2.9 → cursorflow-2.3.1}/pyproject.toml +2 -2
- {cursorflow-2.2.9 → cursorflow-2.3.1}/LICENSE +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/MANIFEST.in +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/__init__.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/auto_init.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/auto_updater.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/action_validator.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/agent.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/auth_handler.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/browser_engine.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/config_validator.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/css_iterator.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/cursor_integration.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/cursorflow.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/error_context_collector.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/error_correlator.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/event_correlator.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/file_change_monitor.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/hmr_detector.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/log_collector.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/log_monitor.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/mockup_comparator.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/persistent_session.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/report_generator.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/core/trace_manager.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/install_cursorflow_rules.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/log_sources/local_file.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/log_sources/ssh_remote.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/post_install.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/rules/__init__.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/rules/cursorflow-installation.mdc +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow/updater.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/cursorflow.egg-info/SOURCES.txt +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/examples/comprehensive_screenshot_example.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/examples/enhanced_screenshot_example.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/examples/hot_reload_css_iteration.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/examples/mockup_comparison_example.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/examples/opensas_example.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/examples/react_example.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/examples/responsive_testing_example.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/examples/v2_comprehensive_demo.py +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/setup.cfg +0 -0
- {cursorflow-2.2.9 → cursorflow-2.3.1}/setup.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: cursorflow
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.3.1
|
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
|
@@ -386,6 +386,24 @@ cursorflow iterate-mockup https://mockup.com/design \
|
|
386
386
|
]'
|
387
387
|
```
|
388
388
|
|
389
|
+
### **Element Analysis & CSS Debugging**
|
390
|
+
```bash
|
391
|
+
# Comprehensive element inspection with full CSS analysis
|
392
|
+
cursorflow inspect --base-url http://localhost:3000 --selector "#messages-panel"
|
393
|
+
|
394
|
+
# Show all computed CSS properties
|
395
|
+
cursorflow inspect -u http://localhost:3000 -s ".card" --verbose
|
396
|
+
|
397
|
+
# Quick dimension check (surgical precision)
|
398
|
+
cursorflow measure --base-url http://localhost:3000 --selector "#panel"
|
399
|
+
|
400
|
+
# Measure multiple elements at once
|
401
|
+
cursorflow measure -u http://localhost:3000 -s "#panel1" -s "#panel2"
|
402
|
+
|
403
|
+
# Verify CSS changes with all properties
|
404
|
+
cursorflow measure -u http://localhost:3000 -s ".button" --verbose
|
405
|
+
```
|
406
|
+
|
389
407
|
### **AI Integration**
|
390
408
|
```bash
|
391
409
|
# Install Cursor AI rules
|
@@ -341,6 +341,24 @@ cursorflow iterate-mockup https://mockup.com/design \
|
|
341
341
|
]'
|
342
342
|
```
|
343
343
|
|
344
|
+
### **Element Analysis & CSS Debugging**
|
345
|
+
```bash
|
346
|
+
# Comprehensive element inspection with full CSS analysis
|
347
|
+
cursorflow inspect --base-url http://localhost:3000 --selector "#messages-panel"
|
348
|
+
|
349
|
+
# Show all computed CSS properties
|
350
|
+
cursorflow inspect -u http://localhost:3000 -s ".card" --verbose
|
351
|
+
|
352
|
+
# Quick dimension check (surgical precision)
|
353
|
+
cursorflow measure --base-url http://localhost:3000 --selector "#panel"
|
354
|
+
|
355
|
+
# Measure multiple elements at once
|
356
|
+
cursorflow measure -u http://localhost:3000 -s "#panel1" -s "#panel2"
|
357
|
+
|
358
|
+
# Verify CSS changes with all properties
|
359
|
+
cursorflow measure -u http://localhost:3000 -s ".button" --verbose
|
360
|
+
```
|
361
|
+
|
344
362
|
### **AI Integration**
|
345
363
|
```bash
|
346
364
|
# Install Cursor AI rules
|
@@ -191,12 +191,22 @@ def test(base_url, path, actions, output, logs, config, verbose, headless, timeo
|
|
191
191
|
console.print(f"[red]❌ Failed to load actions: {e}[/red]")
|
192
192
|
return
|
193
193
|
elif path:
|
194
|
-
# Simple path navigation
|
195
|
-
test_actions = [
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
194
|
+
# Simple path navigation with optional wait conditions
|
195
|
+
test_actions = [{"navigate": path}]
|
196
|
+
|
197
|
+
# Add wait conditions if specified
|
198
|
+
if wait:
|
199
|
+
test_actions.append({"wait_for_timeout": int(wait * 1000)})
|
200
|
+
if wait_for:
|
201
|
+
test_actions.append({"wait_for_selector": wait_for})
|
202
|
+
if wait_for_network_idle:
|
203
|
+
test_actions.append({"wait_for_load_state": "networkidle"})
|
204
|
+
|
205
|
+
# Default wait if none specified
|
206
|
+
if not any([wait, wait_for, wait_for_network_idle]):
|
207
|
+
test_actions.append({"wait_for_selector": "body"})
|
208
|
+
|
209
|
+
test_actions.append({"screenshot": "page_loaded"})
|
200
210
|
console.print(f"📋 Using simple path navigation to [cyan]{path}[/cyan]")
|
201
211
|
else:
|
202
212
|
# Default actions - just navigate to root and screenshot
|
@@ -766,14 +776,21 @@ def sessions(subcommand, name):
|
|
766
776
|
|
767
777
|
@main.command()
|
768
778
|
@click.option('--base-url', '-u', required=True)
|
779
|
+
@click.option('--path', '-p', default='/', help='Path to navigate to')
|
769
780
|
@click.option('--selector', '-s', required=True)
|
770
|
-
|
781
|
+
@click.option('--verbose', '-v', is_flag=True, help='Show all computed styles')
|
782
|
+
def inspect(base_url, path, selector, verbose):
|
771
783
|
"""
|
772
|
-
|
784
|
+
Comprehensive element inspection with full data capture
|
785
|
+
|
786
|
+
Shows computed CSS, dimensions, selectors, and visual context for matching elements.
|
787
|
+
Perfect for CSS debugging and element analysis.
|
773
788
|
|
774
|
-
|
789
|
+
Examples:
|
790
|
+
cursorflow inspect --base-url http://localhost:3000 --selector "#messages-panel"
|
791
|
+
cursorflow inspect -u http://localhost:3000 -p /dashboard -s ".card"
|
775
792
|
"""
|
776
|
-
console.print(f"🔍 Inspecting selector: [cyan]{selector}[/cyan]")
|
793
|
+
console.print(f"🔍 Inspecting selector: [cyan]{selector}[/cyan] at [blue]{path}[/blue]")
|
777
794
|
|
778
795
|
try:
|
779
796
|
from .core.cursorflow import CursorFlow
|
@@ -783,18 +800,268 @@ def inspect(base_url, selector):
|
|
783
800
|
browser_config={'headless': True}
|
784
801
|
)
|
785
802
|
|
786
|
-
#
|
803
|
+
# Comprehensive inspection with full data capture
|
804
|
+
console.print("📸 Capturing comprehensive page data...")
|
787
805
|
results = asyncio.run(flow.execute_and_collect([
|
788
|
-
{"navigate":
|
789
|
-
{"
|
790
|
-
|
791
|
-
"""}
|
806
|
+
{"navigate": path},
|
807
|
+
{"wait_for_selector": "body"},
|
808
|
+
{"screenshot": "inspection"}
|
792
809
|
]))
|
793
810
|
|
794
|
-
|
811
|
+
# Extract element data from comprehensive analysis
|
812
|
+
comprehensive_data = results.get('comprehensive_data', {})
|
813
|
+
dom_analysis = comprehensive_data.get('dom_analysis', {})
|
814
|
+
elements = dom_analysis.get('elements', [])
|
815
|
+
|
816
|
+
# Find matching elements
|
817
|
+
matching_elements = []
|
818
|
+
for element in elements:
|
819
|
+
# Check multiple selector strategies
|
820
|
+
if _element_matches_selector(element, selector):
|
821
|
+
matching_elements.append(element)
|
822
|
+
|
823
|
+
if not matching_elements:
|
824
|
+
console.print(f"[yellow]⚠️ No elements found matching: {selector}[/yellow]")
|
825
|
+
console.print(f"💡 Total elements captured: {len(elements)}")
|
826
|
+
|
827
|
+
# Debug: Show some element IDs/classes to help user
|
828
|
+
if elements and verbose:
|
829
|
+
console.print(f"\n🔍 Debug - Sample of captured elements:")
|
830
|
+
for elem in elements[:10]:
|
831
|
+
elem_id = elem.get('id', '')
|
832
|
+
elem_classes = elem.get('className', '')
|
833
|
+
elem_tag = elem.get('tagName', '')
|
834
|
+
if elem_id or elem_classes:
|
835
|
+
console.print(f" {elem_tag}#{elem_id or '(no-id)'}.{elem_classes or '(no-classes)'}")
|
836
|
+
|
837
|
+
return
|
838
|
+
|
839
|
+
console.print(f"\n✅ Found [bold]{len(matching_elements)}[/bold] matching element(s)\n")
|
840
|
+
|
841
|
+
# Display detailed information for each match
|
842
|
+
for idx, element in enumerate(matching_elements[:5], 1): # Show first 5
|
843
|
+
console.print(f"[bold cyan]═══ Element {idx}/{len(matching_elements)} ═══[/bold cyan]")
|
844
|
+
|
845
|
+
# Basic info
|
846
|
+
tag = element.get('tagName', 'unknown')
|
847
|
+
elem_id = element.get('id', '')
|
848
|
+
classes = element.get('className', '')
|
849
|
+
|
850
|
+
console.print(f"Tag: [yellow]{tag}[/yellow]")
|
851
|
+
if elem_id:
|
852
|
+
console.print(f"ID: [green]#{elem_id}[/green]")
|
853
|
+
if classes:
|
854
|
+
console.print(f"Classes: [blue].{classes}[/blue]")
|
855
|
+
|
856
|
+
# Selectors
|
857
|
+
unique_selector = element.get('uniqueSelector', 'N/A')
|
858
|
+
console.print(f"Unique: [cyan]{unique_selector}[/cyan]")
|
859
|
+
|
860
|
+
# Dimensions
|
861
|
+
bbox = element.get('boundingBox', {})
|
862
|
+
if bbox:
|
863
|
+
console.print(f"\n📐 Dimensions:")
|
864
|
+
console.print(f" Position: x={bbox.get('x', 0):.0f}, y={bbox.get('y', 0):.0f}")
|
865
|
+
console.print(f" Size: {bbox.get('width', 0):.0f}w × {bbox.get('height', 0):.0f}h")
|
866
|
+
|
867
|
+
# Computed styles (key CSS properties)
|
868
|
+
computed = element.get('computedStyles', {})
|
869
|
+
if computed:
|
870
|
+
console.print(f"\n🎨 Key CSS Properties:")
|
871
|
+
|
872
|
+
# Layout
|
873
|
+
display = computed.get('display', 'N/A')
|
874
|
+
position = computed.get('position', 'N/A')
|
875
|
+
console.print(f" display: {display}")
|
876
|
+
console.print(f" position: {position}")
|
877
|
+
|
878
|
+
# Flexbox
|
879
|
+
if 'flex' in computed:
|
880
|
+
console.print(f" flex: {computed.get('flex', 'N/A')}")
|
881
|
+
if 'flexBasis' in computed:
|
882
|
+
console.print(f" flex-basis: {computed.get('flexBasis', 'N/A')}")
|
883
|
+
|
884
|
+
# Dimensions
|
885
|
+
width = computed.get('width', 'N/A')
|
886
|
+
height = computed.get('height', 'N/A')
|
887
|
+
console.print(f" width: {width}")
|
888
|
+
console.print(f" height: {height}")
|
889
|
+
|
890
|
+
# Spacing
|
891
|
+
margin = computed.get('margin', 'N/A')
|
892
|
+
padding = computed.get('padding', 'N/A')
|
893
|
+
if margin != 'N/A':
|
894
|
+
console.print(f" margin: {margin}")
|
895
|
+
if padding != 'N/A':
|
896
|
+
console.print(f" padding: {padding}")
|
897
|
+
|
898
|
+
# Show all styles in verbose mode
|
899
|
+
if verbose:
|
900
|
+
console.print(f"\n📋 All Computed Styles:")
|
901
|
+
for prop, value in sorted(computed.items())[:30]: # Limit to 30
|
902
|
+
console.print(f" {prop}: {value}")
|
903
|
+
|
904
|
+
# Accessibility info
|
905
|
+
accessibility = element.get('accessibility', {})
|
906
|
+
if accessibility:
|
907
|
+
role = accessibility.get('role', 'N/A')
|
908
|
+
is_interactive = accessibility.get('isInteractive', False)
|
909
|
+
console.print(f"\n♿ Accessibility:")
|
910
|
+
console.print(f" Role: {role}")
|
911
|
+
console.print(f" Interactive: {'✅' if is_interactive else '❌'}")
|
912
|
+
|
913
|
+
# Visual context
|
914
|
+
visual = element.get('visual_context', {})
|
915
|
+
if visual:
|
916
|
+
console.print(f"\n👁️ Visual Context:")
|
917
|
+
if visual.get('is_visible'):
|
918
|
+
console.print(f" Visibility: ✅ Visible")
|
919
|
+
else:
|
920
|
+
console.print(f" Visibility: ❌ Hidden")
|
921
|
+
if visual.get('z_index'):
|
922
|
+
console.print(f" Z-index: {visual.get('z_index')}")
|
923
|
+
|
924
|
+
console.print("") # Spacing between elements
|
925
|
+
|
926
|
+
if len(matching_elements) > 5:
|
927
|
+
console.print(f"[dim]... and {len(matching_elements) - 5} more elements[/dim]")
|
928
|
+
|
929
|
+
# Show screenshot location
|
930
|
+
screenshots = results.get('artifacts', {}).get('screenshots', [])
|
931
|
+
if screenshots:
|
932
|
+
screenshot_path = screenshots[0]
|
933
|
+
console.print(f"\n📸 Screenshot saved: [cyan]{screenshot_path}[/cyan]")
|
795
934
|
|
796
935
|
except Exception as e:
|
797
936
|
console.print(f"[red]❌ Inspection failed: {e}[/red]")
|
937
|
+
import traceback
|
938
|
+
console.print(traceback.format_exc())
|
939
|
+
|
940
|
+
def _element_matches_selector(element: Dict, selector: str) -> bool:
|
941
|
+
"""Check if element matches the given selector"""
|
942
|
+
|
943
|
+
# ID selector
|
944
|
+
if selector.startswith('#'):
|
945
|
+
target_id = selector[1:]
|
946
|
+
return element.get('id') == target_id
|
947
|
+
|
948
|
+
# Class selector
|
949
|
+
if selector.startswith('.'):
|
950
|
+
target_class = selector[1:]
|
951
|
+
classes = element.get('className') or '' # Handle None from JSON
|
952
|
+
if not isinstance(classes, str):
|
953
|
+
return False
|
954
|
+
return target_class in classes.split() if classes else False
|
955
|
+
|
956
|
+
# Tag selector
|
957
|
+
tag = element.get('tagName', '').lower()
|
958
|
+
selector_lower = selector.lower()
|
959
|
+
if tag == selector_lower:
|
960
|
+
return True
|
961
|
+
|
962
|
+
# Check unique selector contains the target
|
963
|
+
unique_selector = element.get('uniqueSelector', '').lower()
|
964
|
+
if selector_lower in unique_selector:
|
965
|
+
return True
|
966
|
+
|
967
|
+
return False
|
968
|
+
|
969
|
+
@main.command()
|
970
|
+
@click.option('--base-url', '-u', required=True)
|
971
|
+
@click.option('--path', '-p', default='/', help='Path to navigate to')
|
972
|
+
@click.option('--selector', '-s', required=True, multiple=True, help='Selector(s) to measure (can specify multiple)')
|
973
|
+
@click.option('--verbose', '-v', is_flag=True, help='Show all computed CSS properties')
|
974
|
+
def measure(base_url, path, selector, verbose):
|
975
|
+
"""
|
976
|
+
Surgical element dimension measurement
|
977
|
+
|
978
|
+
Quickly measure width, height, and position of elements.
|
979
|
+
Use --verbose to see all computed CSS properties.
|
980
|
+
|
981
|
+
Examples:
|
982
|
+
cursorflow measure --base-url http://localhost:3000 --selector "#messages-panel"
|
983
|
+
cursorflow measure -u http://localhost:3000 -s "#panel1" -s "#panel2" --verbose
|
984
|
+
"""
|
985
|
+
console.print(f"📏 Measuring element dimensions at [blue]{path}[/blue]\n")
|
986
|
+
|
987
|
+
try:
|
988
|
+
from .core.cursorflow import CursorFlow
|
989
|
+
flow = CursorFlow(
|
990
|
+
base_url=base_url,
|
991
|
+
log_config={'source': 'local', 'paths': []},
|
992
|
+
browser_config={'headless': True}
|
993
|
+
)
|
994
|
+
|
995
|
+
# Use comprehensive data capture but display only dimensions
|
996
|
+
selectors_list = list(selector)
|
997
|
+
|
998
|
+
# Execute with screenshot to get comprehensive data
|
999
|
+
results = asyncio.run(flow.execute_and_collect([
|
1000
|
+
{"navigate": path},
|
1001
|
+
{"wait_for_selector": "body"},
|
1002
|
+
{"screenshot": "measurement"}
|
1003
|
+
]))
|
1004
|
+
|
1005
|
+
# Extract element data from comprehensive analysis
|
1006
|
+
comprehensive_data = results.get('comprehensive_data', {})
|
1007
|
+
dom_analysis = comprehensive_data.get('dom_analysis', {})
|
1008
|
+
elements = dom_analysis.get('elements', [])
|
1009
|
+
|
1010
|
+
# For each selector, find matching elements and display dimensions
|
1011
|
+
for sel in selectors_list:
|
1012
|
+
matching_elements = []
|
1013
|
+
for element in elements:
|
1014
|
+
if _element_matches_selector(element, sel):
|
1015
|
+
matching_elements.append(element)
|
1016
|
+
|
1017
|
+
if not matching_elements:
|
1018
|
+
console.print(f"[yellow]⚠️ {sel}: No elements found[/yellow]\n")
|
1019
|
+
continue
|
1020
|
+
|
1021
|
+
for idx, element in enumerate(matching_elements):
|
1022
|
+
if len(matching_elements) > 1:
|
1023
|
+
console.print(f"[bold cyan]{sel}[/bold cyan] [dim](element {idx + 1}/{len(matching_elements)})[/dim]")
|
1024
|
+
else:
|
1025
|
+
console.print(f"[bold cyan]{sel}[/bold cyan]")
|
1026
|
+
|
1027
|
+
# Dimensions - check both camelCase and snake_case
|
1028
|
+
bbox = element.get('boundingBox') or element.get('visual_context', {}).get('bounding_box')
|
1029
|
+
if bbox:
|
1030
|
+
width = bbox.get('width', 0)
|
1031
|
+
height = bbox.get('height', 0)
|
1032
|
+
x = bbox.get('x', 0)
|
1033
|
+
y = bbox.get('y', 0)
|
1034
|
+
console.print(f" 📐 Rendered: {width:.0f}w × {height:.0f}h")
|
1035
|
+
console.print(f" 📍 Position: x={x:.0f}, y={y:.0f}")
|
1036
|
+
|
1037
|
+
# Computed styles
|
1038
|
+
computed = element.get('computedStyles', {})
|
1039
|
+
if computed:
|
1040
|
+
if verbose:
|
1041
|
+
# Show ALL computed CSS properties
|
1042
|
+
console.print(f" 🎨 Computed CSS (all properties):")
|
1043
|
+
for prop, value in sorted(computed.items()):
|
1044
|
+
console.print(f" {prop}: {value}")
|
1045
|
+
else:
|
1046
|
+
# Show key CSS properties only
|
1047
|
+
console.print(f" 🎨 Display: {computed.get('display', 'N/A')}")
|
1048
|
+
console.print(f" 📦 CSS Width: {computed.get('width', 'N/A')}")
|
1049
|
+
|
1050
|
+
if computed.get('flex'):
|
1051
|
+
console.print(f" 🔧 Flex: {computed.get('flex')}")
|
1052
|
+
if computed.get('flexBasis') and computed.get('flexBasis') != 'auto':
|
1053
|
+
console.print(f" 📏 Flex Base: {computed.get('flexBasis')}")
|
1054
|
+
|
1055
|
+
console.print(f" 💡 Use --verbose to see all {len(computed)} CSS properties")
|
1056
|
+
|
1057
|
+
console.print("")
|
1058
|
+
|
1059
|
+
console.print("✅ Measurement complete")
|
1060
|
+
|
1061
|
+
except Exception as e:
|
1062
|
+
console.print(f"[red]❌ Measurement failed: {e}[/red]")
|
1063
|
+
import traceback
|
1064
|
+
console.print(traceback.format_exc())
|
798
1065
|
|
799
1066
|
@main.command()
|
800
1067
|
@click.option('--base-url', '-u', required=True)
|
@@ -1380,7 +1380,7 @@ class BrowserController:
|
|
1380
1380
|
animationData.transition_details.push({
|
1381
1381
|
element_selector: element.tagName.toLowerCase() +
|
1382
1382
|
(element.id ? '#' + element.id : '') +
|
1383
|
-
(element.className ? '.' + element.className.split(' ').join('.') : ''),
|
1383
|
+
(element.className && typeof element.className === 'string' ? '.' + element.className.split(' ').join('.') : ''),
|
1384
1384
|
transition_property: transitionProperty,
|
1385
1385
|
duration: computedStyle.transitionDuration,
|
1386
1386
|
delay: computedStyle.transitionDelay,
|
@@ -255,8 +255,9 @@ cursorflow test --base-url http://localhost:3000 --actions '[
|
|
255
255
|
### **All CLI Commands:**
|
256
256
|
```bash
|
257
257
|
cursorflow test # Test UI with comprehensive data capture
|
258
|
+
cursorflow inspect # Comprehensive element analysis (CSS, dimensions, accessibility)
|
259
|
+
cursorflow measure # Surgical dimension checking (quick CSS verification)
|
258
260
|
cursorflow rerun # Re-run last test
|
259
|
-
cursorflow inspect # Quick element inspection
|
260
261
|
cursorflow count # Count matching elements
|
261
262
|
cursorflow timeline # View event timeline
|
262
263
|
cursorflow sessions # Manage saved sessions
|
@@ -376,6 +377,54 @@ cursorflow test \
|
|
376
377
|
]'
|
377
378
|
```
|
378
379
|
|
380
|
+
### CSS Debugging & Element Analysis
|
381
|
+
```bash
|
382
|
+
# Comprehensive element inspection (full CSS analysis)
|
383
|
+
cursorflow inspect --base-url http://localhost:3000 --selector "#messages-panel"
|
384
|
+
|
385
|
+
# Output includes:
|
386
|
+
# - Computed CSS (all properties: display, flex, width, etc.)
|
387
|
+
# - Rendered dimensions (actual width × height on screen)
|
388
|
+
# - Position (x, y coordinates)
|
389
|
+
# - Unique selector for targeting
|
390
|
+
# - Accessibility info (role, interactive state)
|
391
|
+
# - Visual context (visibility, z-index)
|
392
|
+
# - Screenshot saved to artifacts
|
393
|
+
|
394
|
+
# Show ALL computed CSS properties (verbose mode)
|
395
|
+
cursorflow inspect -u http://localhost:3000 -p /dashboard -s ".card" --verbose
|
396
|
+
|
397
|
+
# Quick dimension check (surgical precision)
|
398
|
+
cursorflow measure --base-url http://localhost:3000 --selector "#panel"
|
399
|
+
|
400
|
+
# Measure multiple elements at once
|
401
|
+
cursorflow measure -u http://localhost:3000 -s "#panel1" -s "#panel2"
|
402
|
+
|
403
|
+
# Verify CSS changes with all properties
|
404
|
+
cursorflow measure -u http://localhost:3000 -s ".button" --verbose
|
405
|
+
```
|
406
|
+
|
407
|
+
**When to use inspect vs measure:**
|
408
|
+
- **`inspect`**: Deep CSS debugging, complex layout issues, need accessibility info
|
409
|
+
- **`measure`**: Quick dimension verification, CSS change validation, multiple elements
|
410
|
+
|
411
|
+
**Workflow example:**
|
412
|
+
```bash
|
413
|
+
# 1. Quick check dimensions
|
414
|
+
cursorflow measure -u http://localhost:3000 -s "#panel"
|
415
|
+
# Output: 260w × 900h
|
416
|
+
|
417
|
+
# 2. Dimensions seem wrong, get full analysis
|
418
|
+
cursorflow inspect -u http://localhost:3000 -s "#panel" --verbose
|
419
|
+
# Output: Full CSS, flex: 1 1 0%, flex-basis: 260px, etc.
|
420
|
+
|
421
|
+
# 3. Make CSS changes based on insights
|
422
|
+
|
423
|
+
# 4. Verify fix
|
424
|
+
cursorflow measure -u http://localhost:3000 -s "#panel"
|
425
|
+
# Output: 532w × 900h ✅
|
426
|
+
```
|
427
|
+
|
379
428
|
## Analyzing Results
|
380
429
|
|
381
430
|
### **Hot Reload CSS Iteration Results**
|
@@ -181,9 +181,32 @@ cursorflow rerun
|
|
181
181
|
cursorflow rerun --click ".other-element"
|
182
182
|
```
|
183
183
|
|
184
|
-
**Inspect elements:**
|
184
|
+
**Inspect elements (comprehensive data):**
|
185
|
+
```bash
|
186
|
+
# Inspect with full element analysis
|
187
|
+
cursorflow inspect --base-url http://localhost:3000 --selector "#messages-panel"
|
188
|
+
|
189
|
+
# Inspect with custom path
|
190
|
+
cursorflow inspect -u http://localhost:3000 -p /dashboard -s ".card"
|
191
|
+
|
192
|
+
# Show all computed CSS properties
|
193
|
+
cursorflow inspect -u http://localhost:3000 -s ".button" --verbose
|
194
|
+
```
|
195
|
+
|
196
|
+
**Measure element dimensions (surgical precision):**
|
197
|
+
```bash
|
198
|
+
# Quick dimension check
|
199
|
+
cursorflow measure --base-url http://localhost:3000 --selector "#panel"
|
200
|
+
|
201
|
+
# Multiple elements at once
|
202
|
+
cursorflow measure -u http://localhost:3000 -s "#panel1" -s "#panel2"
|
203
|
+
|
204
|
+
# Show all CSS properties
|
205
|
+
cursorflow measure -u http://localhost:3000 -s ".card" --verbose
|
206
|
+
```
|
207
|
+
|
208
|
+
**Count elements:**
|
185
209
|
```bash
|
186
|
-
cursorflow inspect --base-url http://localhost:3000 --selector ".message-item"
|
187
210
|
cursorflow count --base-url http://localhost:3000 --selector ".message-item"
|
188
211
|
```
|
189
212
|
|
@@ -192,6 +215,113 @@ cursorflow count --base-url http://localhost:3000 --selector ".message-item"
|
|
192
215
|
cursorflow timeline --session session_12345
|
193
216
|
```
|
194
217
|
|
218
|
+
### **Element Analysis Commands**
|
219
|
+
|
220
|
+
CursorFlow provides powerful element inspection tools for CSS debugging and layout analysis.
|
221
|
+
|
222
|
+
#### **`inspect` - Comprehensive Element Analysis**
|
223
|
+
|
224
|
+
The `inspect` command captures full page data and displays detailed element information:
|
225
|
+
|
226
|
+
**What you get:**
|
227
|
+
- **Computed CSS** - All browser-computed styles (display, position, flex, dimensions, etc.)
|
228
|
+
- **Dimensions** - Rendered width, height, and position
|
229
|
+
- **Selectors** - Unique CSS selector for targeting
|
230
|
+
- **Accessibility** - Role, interactive state, ARIA attributes
|
231
|
+
- **Visual Context** - Visibility, z-index, viewport position
|
232
|
+
- **Screenshot** - Visual reference saved to artifacts
|
233
|
+
|
234
|
+
**Example output:**
|
235
|
+
```
|
236
|
+
═══ Element 1/1 ═══
|
237
|
+
Tag: div
|
238
|
+
ID: #messages-panel
|
239
|
+
Classes: .console-panel.message-list-panel
|
240
|
+
|
241
|
+
📐 Dimensions:
|
242
|
+
Position: x=320, y=73
|
243
|
+
Size: 532w × 927h
|
244
|
+
|
245
|
+
🎨 Key CSS Properties:
|
246
|
+
display: flex
|
247
|
+
flex: 1 1 0%
|
248
|
+
flex-basis: 260px
|
249
|
+
width: 532px
|
250
|
+
|
251
|
+
♿ Accessibility:
|
252
|
+
Role: None
|
253
|
+
Interactive: ❌
|
254
|
+
|
255
|
+
👁️ Visual Context:
|
256
|
+
Visibility: ✅ Visible
|
257
|
+
|
258
|
+
📸 Screenshot saved: .cursorflow/artifacts/screenshots/inspection.png
|
259
|
+
```
|
260
|
+
|
261
|
+
**Use cases:**
|
262
|
+
- Debug CSS layout issues
|
263
|
+
- Verify flex/grid calculations
|
264
|
+
- Check computed vs authored styles
|
265
|
+
- Find optimal selectors for automation
|
266
|
+
- Analyze element visibility and positioning
|
267
|
+
|
268
|
+
#### **`measure` - Surgical Dimension Checking**
|
269
|
+
|
270
|
+
The `measure` command provides quick dimension and CSS checks without verbose output:
|
271
|
+
|
272
|
+
**What you get:**
|
273
|
+
- **Rendered dimensions** - Actual width × height on screen
|
274
|
+
- **Position** - x, y coordinates
|
275
|
+
- **Key CSS** - display, width, flex properties
|
276
|
+
- **Multiple elements** - Measure several at once
|
277
|
+
- **All CSS (--verbose)** - Complete computed styles (76+ properties)
|
278
|
+
|
279
|
+
**Example output:**
|
280
|
+
```
|
281
|
+
h1
|
282
|
+
📐 Rendered: 600w × 38h
|
283
|
+
📍 Position: x=420, y=133
|
284
|
+
🎨 Display: block
|
285
|
+
📦 CSS Width: 600px
|
286
|
+
🔧 Flex: 0 1 auto
|
287
|
+
💡 Use --verbose to see all 76 CSS properties
|
288
|
+
```
|
289
|
+
|
290
|
+
**Use cases:**
|
291
|
+
- Verify CSS changes took effect
|
292
|
+
- Check flex layout calculations
|
293
|
+
- Compare dimensions across breakpoints
|
294
|
+
- Quick dimension reference during development
|
295
|
+
- Validate responsive behavior
|
296
|
+
|
297
|
+
#### **Comparison: inspect vs measure**
|
298
|
+
|
299
|
+
| Feature | `inspect` | `measure` |
|
300
|
+
|---------|-----------|-----------|
|
301
|
+
| **Purpose** | Comprehensive analysis | Quick dimension check |
|
302
|
+
| **Output** | Detailed, multi-section | Concise, focused |
|
303
|
+
| **Screenshot** | Always included | Captured but not shown |
|
304
|
+
| **Use when** | Debugging complex CSS | Verifying dimensions |
|
305
|
+
| **Speed** | ~3 seconds | ~2 seconds |
|
306
|
+
| **Multiple elements** | One at a time | Multiple with `-s` flags |
|
307
|
+
|
308
|
+
**Workflow example:**
|
309
|
+
```bash
|
310
|
+
# 1. Use measure for quick check
|
311
|
+
cursorflow measure -u http://localhost:3000 -s "#panel"
|
312
|
+
# Output: 260w × 900h
|
313
|
+
|
314
|
+
# 2. If dimensions seem wrong, use inspect for full analysis
|
315
|
+
cursorflow inspect -u http://localhost:3000 -s "#panel" --verbose
|
316
|
+
# Output: Full CSS, accessibility, visual context, screenshot
|
317
|
+
|
318
|
+
# 3. Make CSS changes based on insights
|
319
|
+
|
320
|
+
# 4. Verify with measure again
|
321
|
+
cursorflow measure -u http://localhost:3000 -s "#panel"
|
322
|
+
# Output: 532w × 900h ✅ Fixed!
|
323
|
+
```
|
324
|
+
|
195
325
|
### **Artifact Management**
|
196
326
|
|
197
327
|
CursorFlow generates screenshots, traces, and session data. Clean up regularly:
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "cursorflow"
|
7
|
-
version = "2.
|
7
|
+
version = "2.3.1"
|
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 = "3.
|
75
|
+
python_version = "2.3.1"
|
76
76
|
warn_return_any = true
|
77
77
|
warn_unused_configs = true
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|