cursorflow 2.2.9__py3-none-any.whl → 2.3.1__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 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
- {"navigate": path},
197
- {"wait_for_selector": "body"},
198
- {"screenshot": "page_loaded"}
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
- def inspect(base_url, selector):
781
+ @click.option('--verbose', '-v', is_flag=True, help='Show all computed styles')
782
+ def inspect(base_url, path, selector, verbose):
771
783
  """
772
- Quick element inspection without full test
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
- Phase 3.5: Inspect selector and show matching elements
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
- # Quick inspection
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
- {"evaluate": f"""
790
- document.querySelectorAll('{selector}').length
791
- """}
806
+ {"navigate": path},
807
+ {"wait_for_selector": "body"},
808
+ {"screenshot": "inspection"}
792
809
  ]))
793
810
 
794
- console.print(f"✅ Found matches for: {selector}")
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**
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cursorflow
3
- Version: 2.2.9
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
@@ -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=cRxhu48AwQfpO48qlU2B29Vi_jfUIXFe5bvi8LS8poA,50423
4
+ cursorflow/cli.py,sha256=rj5XCml0C8e3SzyUTTFjFVkniu-Mrvbp44Yl81AXupk,62757
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=mfJ5a6-996TC6Z2CHNxxQUQPPqPjPWAvL1njTONwqsA,147423
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=JVj-Xgura1rIfHaR5W_GHy6mBVlYCgE922RtuRVEJvg,21383
33
- cursorflow-2.2.9.dist-info/licenses/LICENSE,sha256=e4QbjAsj3bW-xgQOvQelr8sGLYDoqc48k6cKgCr_pBU,1080
34
- cursorflow-2.2.9.dist-info/METADATA,sha256=KqrosPHkiYF_w5liQVyPt1MlbEWgASl7yunVhdMSGAk,14165
35
- cursorflow-2.2.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
36
- cursorflow-2.2.9.dist-info/entry_points.txt,sha256=-Ed_n4Uff7wClEtWS-Py6xmQabecB9f0QAOjX0w7ljA,51
37
- cursorflow-2.2.9.dist-info/top_level.txt,sha256=t1UZwRyZP4u-ng2CEcNHmk_ZT4ibQxoihB2IjTF7ovc,11
38
- cursorflow-2.2.9.dist-info/RECORD,,
32
+ cursorflow/rules/cursorflow-usage.mdc,sha256=8TUeQ1hq2fTlgPqUBYOVBXrdEN0BR0Xp0d_1L-eUsME,23150
33
+ cursorflow-2.3.1.dist-info/licenses/LICENSE,sha256=e4QbjAsj3bW-xgQOvQelr8sGLYDoqc48k6cKgCr_pBU,1080
34
+ cursorflow-2.3.1.dist-info/METADATA,sha256=KDOTMFdwdwMtLOJwNkie3WVewQxjFYZ1_yJNk4jJSE8,14793
35
+ cursorflow-2.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
36
+ cursorflow-2.3.1.dist-info/entry_points.txt,sha256=-Ed_n4Uff7wClEtWS-Py6xmQabecB9f0QAOjX0w7ljA,51
37
+ cursorflow-2.3.1.dist-info/top_level.txt,sha256=t1UZwRyZP4u-ng2CEcNHmk_ZT4ibQxoihB2IjTF7ovc,11
38
+ cursorflow-2.3.1.dist-info/RECORD,,