cursorflow 2.2.8__py3-none-any.whl → 2.3.0__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.
- cursorflow/cli.py +270 -16
- cursorflow/core/browser_controller.py +1 -1
- cursorflow/rules/cursorflow-usage.mdc +50 -1
- {cursorflow-2.2.8.dist-info → cursorflow-2.3.0.dist-info}/METADATA +22 -13
- {cursorflow-2.2.8.dist-info → cursorflow-2.3.0.dist-info}/RECORD +9 -9
- {cursorflow-2.2.8.dist-info → cursorflow-2.3.0.dist-info}/WHEEL +0 -0
- {cursorflow-2.2.8.dist-info → cursorflow-2.3.0.dist-info}/entry_points.txt +0 -0
- {cursorflow-2.2.8.dist-info → cursorflow-2.3.0.dist-info}/licenses/LICENSE +0 -0
- {cursorflow-2.2.8.dist-info → cursorflow-2.3.0.dist-info}/top_level.txt +0 -0
cursorflow/cli.py
CHANGED
@@ -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,255 @@ 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
|
+
return
|
827
|
+
|
828
|
+
console.print(f"\n✅ Found [bold]{len(matching_elements)}[/bold] matching element(s)\n")
|
829
|
+
|
830
|
+
# Display detailed information for each match
|
831
|
+
for idx, element in enumerate(matching_elements[:5], 1): # Show first 5
|
832
|
+
console.print(f"[bold cyan]═══ Element {idx}/{len(matching_elements)} ═══[/bold cyan]")
|
833
|
+
|
834
|
+
# Basic info
|
835
|
+
tag = element.get('tagName', 'unknown')
|
836
|
+
elem_id = element.get('id', '')
|
837
|
+
classes = element.get('className', '')
|
838
|
+
|
839
|
+
console.print(f"Tag: [yellow]{tag}[/yellow]")
|
840
|
+
if elem_id:
|
841
|
+
console.print(f"ID: [green]#{elem_id}[/green]")
|
842
|
+
if classes:
|
843
|
+
console.print(f"Classes: [blue].{classes}[/blue]")
|
844
|
+
|
845
|
+
# Selectors
|
846
|
+
unique_selector = element.get('uniqueSelector', 'N/A')
|
847
|
+
console.print(f"Unique: [cyan]{unique_selector}[/cyan]")
|
848
|
+
|
849
|
+
# Dimensions
|
850
|
+
bbox = element.get('boundingBox', {})
|
851
|
+
if bbox:
|
852
|
+
console.print(f"\n📐 Dimensions:")
|
853
|
+
console.print(f" Position: x={bbox.get('x', 0):.0f}, y={bbox.get('y', 0):.0f}")
|
854
|
+
console.print(f" Size: {bbox.get('width', 0):.0f}w × {bbox.get('height', 0):.0f}h")
|
855
|
+
|
856
|
+
# Computed styles (key CSS properties)
|
857
|
+
computed = element.get('computedStyles', {})
|
858
|
+
if computed:
|
859
|
+
console.print(f"\n🎨 Key CSS Properties:")
|
860
|
+
|
861
|
+
# Layout
|
862
|
+
display = computed.get('display', 'N/A')
|
863
|
+
position = computed.get('position', 'N/A')
|
864
|
+
console.print(f" display: {display}")
|
865
|
+
console.print(f" position: {position}")
|
866
|
+
|
867
|
+
# Flexbox
|
868
|
+
if 'flex' in computed:
|
869
|
+
console.print(f" flex: {computed.get('flex', 'N/A')}")
|
870
|
+
if 'flexBasis' in computed:
|
871
|
+
console.print(f" flex-basis: {computed.get('flexBasis', 'N/A')}")
|
872
|
+
|
873
|
+
# Dimensions
|
874
|
+
width = computed.get('width', 'N/A')
|
875
|
+
height = computed.get('height', 'N/A')
|
876
|
+
console.print(f" width: {width}")
|
877
|
+
console.print(f" height: {height}")
|
878
|
+
|
879
|
+
# Spacing
|
880
|
+
margin = computed.get('margin', 'N/A')
|
881
|
+
padding = computed.get('padding', 'N/A')
|
882
|
+
if margin != 'N/A':
|
883
|
+
console.print(f" margin: {margin}")
|
884
|
+
if padding != 'N/A':
|
885
|
+
console.print(f" padding: {padding}")
|
886
|
+
|
887
|
+
# Show all styles in verbose mode
|
888
|
+
if verbose:
|
889
|
+
console.print(f"\n📋 All Computed Styles:")
|
890
|
+
for prop, value in sorted(computed.items())[:30]: # Limit to 30
|
891
|
+
console.print(f" {prop}: {value}")
|
892
|
+
|
893
|
+
# Accessibility info
|
894
|
+
accessibility = element.get('accessibility', {})
|
895
|
+
if accessibility:
|
896
|
+
role = accessibility.get('role', 'N/A')
|
897
|
+
is_interactive = accessibility.get('isInteractive', False)
|
898
|
+
console.print(f"\n♿ Accessibility:")
|
899
|
+
console.print(f" Role: {role}")
|
900
|
+
console.print(f" Interactive: {'✅' if is_interactive else '❌'}")
|
901
|
+
|
902
|
+
# Visual context
|
903
|
+
visual = element.get('visual_context', {})
|
904
|
+
if visual:
|
905
|
+
console.print(f"\n👁️ Visual Context:")
|
906
|
+
if visual.get('is_visible'):
|
907
|
+
console.print(f" Visibility: ✅ Visible")
|
908
|
+
else:
|
909
|
+
console.print(f" Visibility: ❌ Hidden")
|
910
|
+
if visual.get('z_index'):
|
911
|
+
console.print(f" Z-index: {visual.get('z_index')}")
|
912
|
+
|
913
|
+
console.print("") # Spacing between elements
|
914
|
+
|
915
|
+
if len(matching_elements) > 5:
|
916
|
+
console.print(f"[dim]... and {len(matching_elements) - 5} more elements[/dim]")
|
917
|
+
|
918
|
+
# Show screenshot location
|
919
|
+
screenshots = results.get('artifacts', {}).get('screenshots', [])
|
920
|
+
if screenshots:
|
921
|
+
screenshot_path = screenshots[0]
|
922
|
+
console.print(f"\n📸 Screenshot saved: [cyan]{screenshot_path}[/cyan]")
|
795
923
|
|
796
924
|
except Exception as e:
|
797
925
|
console.print(f"[red]❌ Inspection failed: {e}[/red]")
|
926
|
+
import traceback
|
927
|
+
console.print(traceback.format_exc())
|
928
|
+
|
929
|
+
def _element_matches_selector(element: Dict, selector: str) -> bool:
|
930
|
+
"""Check if element matches the given selector"""
|
931
|
+
|
932
|
+
# ID selector
|
933
|
+
if selector.startswith('#'):
|
934
|
+
target_id = selector[1:]
|
935
|
+
return element.get('id') == target_id
|
936
|
+
|
937
|
+
# Class selector
|
938
|
+
if selector.startswith('.'):
|
939
|
+
target_class = selector[1:]
|
940
|
+
classes = element.get('className', '')
|
941
|
+
return target_class in classes.split()
|
942
|
+
|
943
|
+
# Tag selector
|
944
|
+
tag = element.get('tagName', '').lower()
|
945
|
+
selector_lower = selector.lower()
|
946
|
+
if tag == selector_lower:
|
947
|
+
return True
|
948
|
+
|
949
|
+
# Check unique selector contains the target
|
950
|
+
unique_selector = element.get('uniqueSelector', '').lower()
|
951
|
+
if selector_lower in unique_selector:
|
952
|
+
return True
|
953
|
+
|
954
|
+
return False
|
955
|
+
|
956
|
+
@main.command()
|
957
|
+
@click.option('--base-url', '-u', required=True)
|
958
|
+
@click.option('--path', '-p', default='/', help='Path to navigate to')
|
959
|
+
@click.option('--selector', '-s', required=True, multiple=True, help='Selector(s) to measure (can specify multiple)')
|
960
|
+
@click.option('--verbose', '-v', is_flag=True, help='Show all computed CSS properties')
|
961
|
+
def measure(base_url, path, selector, verbose):
|
962
|
+
"""
|
963
|
+
Surgical element dimension measurement
|
964
|
+
|
965
|
+
Quickly measure width, height, and position of elements.
|
966
|
+
Use --verbose to see all computed CSS properties.
|
967
|
+
|
968
|
+
Examples:
|
969
|
+
cursorflow measure --base-url http://localhost:3000 --selector "#messages-panel"
|
970
|
+
cursorflow measure -u http://localhost:3000 -s "#panel1" -s "#panel2" --verbose
|
971
|
+
"""
|
972
|
+
console.print(f"📏 Measuring element dimensions at [blue]{path}[/blue]\n")
|
973
|
+
|
974
|
+
try:
|
975
|
+
from .core.cursorflow import CursorFlow
|
976
|
+
flow = CursorFlow(
|
977
|
+
base_url=base_url,
|
978
|
+
log_config={'source': 'local', 'paths': []},
|
979
|
+
browser_config={'headless': True}
|
980
|
+
)
|
981
|
+
|
982
|
+
# Use comprehensive data capture but display only dimensions
|
983
|
+
selectors_list = list(selector)
|
984
|
+
|
985
|
+
# Execute with screenshot to get comprehensive data
|
986
|
+
results = asyncio.run(flow.execute_and_collect([
|
987
|
+
{"navigate": path},
|
988
|
+
{"wait_for_selector": "body"},
|
989
|
+
{"screenshot": "measurement"}
|
990
|
+
]))
|
991
|
+
|
992
|
+
# Extract element data from comprehensive analysis
|
993
|
+
comprehensive_data = results.get('comprehensive_data', {})
|
994
|
+
dom_analysis = comprehensive_data.get('dom_analysis', {})
|
995
|
+
elements = dom_analysis.get('elements', [])
|
996
|
+
|
997
|
+
# For each selector, find matching elements and display dimensions
|
998
|
+
for sel in selectors_list:
|
999
|
+
matching_elements = []
|
1000
|
+
for element in elements:
|
1001
|
+
if _element_matches_selector(element, sel):
|
1002
|
+
matching_elements.append(element)
|
1003
|
+
|
1004
|
+
if not matching_elements:
|
1005
|
+
console.print(f"[yellow]⚠️ {sel}: No elements found[/yellow]\n")
|
1006
|
+
continue
|
1007
|
+
|
1008
|
+
for idx, element in enumerate(matching_elements):
|
1009
|
+
if len(matching_elements) > 1:
|
1010
|
+
console.print(f"[bold cyan]{sel}[/bold cyan] [dim](element {idx + 1}/{len(matching_elements)})[/dim]")
|
1011
|
+
else:
|
1012
|
+
console.print(f"[bold cyan]{sel}[/bold cyan]")
|
1013
|
+
|
1014
|
+
# Dimensions - check both camelCase and snake_case
|
1015
|
+
bbox = element.get('boundingBox') or element.get('visual_context', {}).get('bounding_box')
|
1016
|
+
if bbox:
|
1017
|
+
width = bbox.get('width', 0)
|
1018
|
+
height = bbox.get('height', 0)
|
1019
|
+
x = bbox.get('x', 0)
|
1020
|
+
y = bbox.get('y', 0)
|
1021
|
+
console.print(f" 📐 Rendered: {width:.0f}w × {height:.0f}h")
|
1022
|
+
console.print(f" 📍 Position: x={x:.0f}, y={y:.0f}")
|
1023
|
+
|
1024
|
+
# Computed styles
|
1025
|
+
computed = element.get('computedStyles', {})
|
1026
|
+
if computed:
|
1027
|
+
if verbose:
|
1028
|
+
# Show ALL computed CSS properties
|
1029
|
+
console.print(f" 🎨 Computed CSS (all properties):")
|
1030
|
+
for prop, value in sorted(computed.items()):
|
1031
|
+
console.print(f" {prop}: {value}")
|
1032
|
+
else:
|
1033
|
+
# Show key CSS properties only
|
1034
|
+
console.print(f" 🎨 Display: {computed.get('display', 'N/A')}")
|
1035
|
+
console.print(f" 📦 CSS Width: {computed.get('width', 'N/A')}")
|
1036
|
+
|
1037
|
+
if computed.get('flex'):
|
1038
|
+
console.print(f" 🔧 Flex: {computed.get('flex')}")
|
1039
|
+
if computed.get('flexBasis') and computed.get('flexBasis') != 'auto':
|
1040
|
+
console.print(f" 📏 Flex Base: {computed.get('flexBasis')}")
|
1041
|
+
|
1042
|
+
console.print(f" 💡 Use --verbose to see all {len(computed)} CSS properties")
|
1043
|
+
|
1044
|
+
console.print("")
|
1045
|
+
|
1046
|
+
console.print("✅ Measurement complete")
|
1047
|
+
|
1048
|
+
except Exception as e:
|
1049
|
+
console.print(f"[red]❌ Measurement failed: {e}[/red]")
|
1050
|
+
import traceback
|
1051
|
+
console.print(traceback.format_exc())
|
798
1052
|
|
799
1053
|
@main.command()
|
800
1054
|
@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**
|
@@ -1,11 +1,11 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: cursorflow
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.3.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
|
7
7
|
Project-URL: Homepage, https://github.com/haley-marketing-group/cursorflow
|
8
|
-
Project-URL: Documentation, https://cursorflow.
|
8
|
+
Project-URL: Documentation, https://cursorflow.dev
|
9
9
|
Project-URL: Repository, https://github.com/haley-marketing-group/cursorflow
|
10
10
|
Keywords: ui-testing,automation,cursor,ai,web-testing,css-iteration,hot-reload,hmr,element-intelligence,page-analysis,error-context
|
11
11
|
Classifier: Development Status :: 5 - Production/Stable
|
@@ -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
|
@@ -397,14 +415,6 @@ cursorflow update
|
|
397
415
|
|
398
416
|
## 🧠 Why This Matters
|
399
417
|
|
400
|
-
### **For Job Board v4 Testing:**
|
401
|
-
✅ **Real API response times** from `/ajax_rq.smpl?fn=gjapi_typeahead`
|
402
|
-
✅ **Actual network failures** when they occur
|
403
|
-
✅ **Real browser console errors** from production code
|
404
|
-
✅ **Genuine performance metrics** under real load
|
405
|
-
|
406
|
-
❌ **With mocking:** You'd never know the typeahead is slow in production!
|
407
|
-
|
408
418
|
### **For Any Web Application:**
|
409
419
|
- **Trust your test results** - they reflect actual behavior
|
410
420
|
- **Find real performance bottlenecks** - no artificial speed boosts
|
@@ -427,9 +437,8 @@ cursorflow update
|
|
427
437
|
|
428
438
|
## 📖 Documentation
|
429
439
|
|
430
|
-
- **[
|
431
|
-
- **[Examples](examples/)** - Practical usage examples
|
432
|
-
- **[API Reference](docs/api/)** - Complete Python API documentation
|
440
|
+
- **[Usage Guide](docs/user/USAGE_GUIDE.md)** - Complete usage documentation (included in pip install)
|
441
|
+
- **[Examples](examples/)** - Practical usage examples (included in pip install)
|
433
442
|
|
434
443
|
## 🎪 The CursorFlow Advantage
|
435
444
|
|
@@ -1,14 +1,14 @@
|
|
1
1
|
cursorflow/__init__.py,sha256=5G0Zm1HeS4oGx9S9E5GFRon5gduljQMlJhs1XEBUuE4,2763
|
2
2
|
cursorflow/auto_init.py,sha256=dXQaXXiXe4wkUP-jd8fcJ5fYVt7ASdTb47b7SzXymOM,6122
|
3
3
|
cursorflow/auto_updater.py,sha256=oQ12TIMZ6Cm3HF-x9iRWFtvOLkRh-JWPqitS69-4roE,7851
|
4
|
-
cursorflow/cli.py,sha256=
|
4
|
+
cursorflow/cli.py,sha256=l8TTcX6ve5Zx4sAOkdX5P1OChrZkDjvkix4Fbgdf-VE,62069
|
5
5
|
cursorflow/install_cursorflow_rules.py,sha256=DsZ0680y9JMuTKFXjdgYtOKIEAjBMsdwL8LmA9WEb5A,11864
|
6
6
|
cursorflow/post_install.py,sha256=WieBiKWG0qBAQpF8iMVWUyb9Fr2Xky9qECTMPrlAbpE,2678
|
7
7
|
cursorflow/updater.py,sha256=SroSQHQi5cYyzcOK_bf-WzmQmE7yeOs8qo3r__j-Z6E,19583
|
8
8
|
cursorflow/core/action_validator.py,sha256=SCk3w_62D1y0cCRDOajK8L44-abSj_KpnUBgR_yNVW4,6846
|
9
9
|
cursorflow/core/agent.py,sha256=f3lecgEzDRDdGTVccAtorpLGfNJJ49bbsQAmgr0vNGg,10136
|
10
10
|
cursorflow/core/auth_handler.py,sha256=oRafO6ZdxoHryBIvHsrNV8TECed4GXpJsdEiH0KdPPk,17149
|
11
|
-
cursorflow/core/browser_controller.py,sha256=
|
11
|
+
cursorflow/core/browser_controller.py,sha256=Efx48lxIz6MYZI8bHhIDpP_hqKDxeHSLvK8vgiPaXBM,147464
|
12
12
|
cursorflow/core/browser_engine.py,sha256=7N9hPOyDrEhLWYgZW2981N9gKlHF6Lbp7D7h0zBzuz8,14851
|
13
13
|
cursorflow/core/config_validator.py,sha256=HRtONSOmM0Xxt3-ok3xwnBADRiNnI0nNOMaS2OqOkDk,7286
|
14
14
|
cursorflow/core/css_iterator.py,sha256=whLCIwbHZEWaH1HCbmqhNX5zrh_fL-r3hsxKjYsukcE,16478
|
@@ -29,10 +29,10 @@ cursorflow/log_sources/local_file.py,sha256=GVnhsaifIdc41twXwbxRM9-fBeRDsknDpk5I
|
|
29
29
|
cursorflow/log_sources/ssh_remote.py,sha256=_Kwh0bhRpKgq-0c98oaX2hN6h9cT-wCHlqY5NiWVCoY,8388
|
30
30
|
cursorflow/rules/__init__.py,sha256=gPcA-IkhXj03sl7cvZV0wwo7CtEkcyuKs4y0F5oQbqE,458
|
31
31
|
cursorflow/rules/cursorflow-installation.mdc,sha256=D55pzzDPAVVbE3gAtKPUGoT-2fvB-FI2l6yrTdzUIEo,10208
|
32
|
-
cursorflow/rules/cursorflow-usage.mdc,sha256=
|
33
|
-
cursorflow-2.
|
34
|
-
cursorflow-2.
|
35
|
-
cursorflow-2.
|
36
|
-
cursorflow-2.
|
37
|
-
cursorflow-2.
|
38
|
-
cursorflow-2.
|
32
|
+
cursorflow/rules/cursorflow-usage.mdc,sha256=8TUeQ1hq2fTlgPqUBYOVBXrdEN0BR0Xp0d_1L-eUsME,23150
|
33
|
+
cursorflow-2.3.0.dist-info/licenses/LICENSE,sha256=e4QbjAsj3bW-xgQOvQelr8sGLYDoqc48k6cKgCr_pBU,1080
|
34
|
+
cursorflow-2.3.0.dist-info/METADATA,sha256=hC0JZcjfBUi9MolXNXB80aX_YU23nH0Zgnr350bYKlI,14793
|
35
|
+
cursorflow-2.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
36
|
+
cursorflow-2.3.0.dist-info/entry_points.txt,sha256=-Ed_n4Uff7wClEtWS-Py6xmQabecB9f0QAOjX0w7ljA,51
|
37
|
+
cursorflow-2.3.0.dist-info/top_level.txt,sha256=t1UZwRyZP4u-ng2CEcNHmk_ZT4ibQxoihB2IjTF7ovc,11
|
38
|
+
cursorflow-2.3.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|