cursorflow 2.4.1__tar.gz → 2.4.3__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.4.1 → cursorflow-2.4.3}/PKG-INFO +1 -1
  2. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/cli.py +55 -12
  3. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/browser_controller.py +6 -1
  4. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/mockup_comparator.py +13 -8
  5. {cursorflow-2.4.1 → cursorflow-2.4.3}/pyproject.toml +2 -2
  6. {cursorflow-2.4.1 → cursorflow-2.4.3}/LICENSE +0 -0
  7. {cursorflow-2.4.1 → cursorflow-2.4.3}/MANIFEST.in +0 -0
  8. {cursorflow-2.4.1 → cursorflow-2.4.3}/README.md +0 -0
  9. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/__init__.py +0 -0
  10. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/auto_init.py +0 -0
  11. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/auto_updater.py +0 -0
  12. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/action_validator.py +0 -0
  13. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/agent.py +0 -0
  14. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/auth_handler.py +0 -0
  15. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/browser_engine.py +0 -0
  16. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/config_validator.py +0 -0
  17. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/css_iterator.py +0 -0
  18. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/cursor_integration.py +0 -0
  19. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/cursorflow.py +0 -0
  20. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/error_context_collector.py +0 -0
  21. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/error_correlator.py +0 -0
  22. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/event_correlator.py +0 -0
  23. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/file_change_monitor.py +0 -0
  24. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/hmr_detector.py +0 -0
  25. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/log_collector.py +0 -0
  26. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/log_monitor.py +0 -0
  27. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/persistent_session.py +0 -0
  28. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/report_generator.py +0 -0
  29. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/trace_manager.py +0 -0
  30. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/install_cursorflow_rules.py +0 -0
  31. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/log_sources/local_file.py +0 -0
  32. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/log_sources/ssh_remote.py +0 -0
  33. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/post_install.py +0 -0
  34. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/rules/__init__.py +0 -0
  35. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/rules/cursorflow-installation.mdc +0 -0
  36. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/rules/cursorflow-usage.mdc +0 -0
  37. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/updater.py +0 -0
  38. {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow.egg-info/SOURCES.txt +0 -0
  39. {cursorflow-2.4.1 → cursorflow-2.4.3}/docs/user/USAGE_GUIDE.md +0 -0
  40. {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/comprehensive_screenshot_example.py +0 -0
  41. {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/element_inspection_example.py +0 -0
  42. {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/element_measurement_example.py +0 -0
  43. {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/enhanced_screenshot_example.py +0 -0
  44. {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/hot_reload_css_iteration.py +0 -0
  45. {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/mockup_comparison_example.py +0 -0
  46. {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/opensas_example.py +0 -0
  47. {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/react_example.py +0 -0
  48. {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/responsive_testing_example.py +0 -0
  49. {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/v2_comprehensive_demo.py +0 -0
  50. {cursorflow-2.4.1 → cursorflow-2.4.3}/setup.cfg +0 -0
  51. {cursorflow-2.4.1 → cursorflow-2.4.3}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cursorflow
3
- Version: 2.4.1
3
+ Version: 2.4.3
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
@@ -404,6 +404,7 @@ def compare_mockup(mockup_url, base_url, mockup_actions, implementation_actions,
404
404
  # Initialize CursorFlow
405
405
  try:
406
406
  from .core.cursorflow import CursorFlow
407
+
407
408
  flow = CursorFlow(
408
409
  base_url=base_url,
409
410
  log_config={'source': 'local', 'paths': ['logs/app.log']},
@@ -440,9 +441,16 @@ def compare_mockup(mockup_url, base_url, mockup_actions, implementation_actions,
440
441
  for i, rec in enumerate(recommendations[:3]): # Show first 3
441
442
  console.print(f" {i+1}. {rec.get('description', 'No description')}")
442
443
 
443
- # Save results
444
+ # Save results with numpy type handling
444
445
  with open(output, 'w') as f:
445
- json.dump(results, f, indent=2, default=str)
446
+ def json_serializer(obj):
447
+ # Handle numpy types
448
+ if hasattr(obj, 'item'): # numpy scalars (bool_, int_, float_)
449
+ return obj.item()
450
+ if hasattr(obj, 'tolist'): # numpy arrays
451
+ return obj.tolist()
452
+ return str(obj)
453
+ json.dump(results, f, indent=2, default=json_serializer)
446
454
 
447
455
  console.print(f"💾 Full results saved to: [cyan]{output}[/cyan]")
448
456
  console.print(f"📁 Visual diffs stored in: [cyan].cursorflow/artifacts/[/cyan]")
@@ -915,12 +923,25 @@ def inspect(base_url, path, selector, verbose):
915
923
  visual = element.get('visual_context', {})
916
924
  if visual:
917
925
  console.print(f"\n👁️ Visual Context:")
918
- if visual.get('is_visible'):
926
+ # Check nested visibility structure
927
+ visibility = visual.get('visibility', {})
928
+ is_visible = visibility.get('is_visible', False)
929
+ is_in_viewport = visibility.get('is_in_viewport', False)
930
+
931
+ if is_visible:
919
932
  console.print(f" Visibility: ✅ Visible")
933
+ if is_in_viewport:
934
+ console.print(f" In Viewport: ✅ Yes")
935
+ else:
936
+ console.print(f" In Viewport: ⬇️ Below fold")
920
937
  else:
921
938
  console.print(f" Visibility: ❌ Hidden")
922
- if visual.get('z_index'):
923
- console.print(f" Z-index: {visual.get('z_index')}")
939
+
940
+ # Z-index from layering info
941
+ layering = visual.get('layering', {})
942
+ z_index = layering.get('z_index')
943
+ if z_index and z_index != 'auto':
944
+ console.print(f" Z-index: {z_index}")
924
945
 
925
946
  console.print("") # Spacing between elements
926
947
 
@@ -1067,14 +1088,19 @@ def measure(base_url, path, selector, verbose):
1067
1088
 
1068
1089
  @main.command()
1069
1090
  @click.option('--base-url', '-u', required=True)
1091
+ @click.option('--path', '-p', default='/', help='Path to navigate to')
1070
1092
  @click.option('--selector', '-s', required=True)
1071
- def count(base_url, selector):
1093
+ def count(base_url, path, selector):
1072
1094
  """
1073
1095
  Quick element count without full test
1074
1096
 
1075
- Phase 3.5: Count matching elements
1097
+ Counts how many elements match the given selector.
1098
+
1099
+ Examples:
1100
+ cursorflow count --base-url http://localhost:3000 --selector ".message-item"
1101
+ cursorflow count -u http://localhost:3000 -p /dashboard -s "button"
1076
1102
  """
1077
- console.print(f"🔢 Counting selector: [cyan]{selector}[/cyan]")
1103
+ console.print(f"🔢 Counting selector: [cyan]{selector}[/cyan] at [blue]{path}[/blue]\n")
1078
1104
 
1079
1105
  try:
1080
1106
  from .core.cursorflow import CursorFlow
@@ -1084,15 +1110,32 @@ def count(base_url, selector):
1084
1110
  browser_config={'headless': True}
1085
1111
  )
1086
1112
 
1087
- # Quick count
1088
- asyncio.run(flow.execute_and_collect([
1089
- {"navigate": "/"}
1113
+ # Execute with screenshot to get comprehensive data
1114
+ results = asyncio.run(flow.execute_and_collect([
1115
+ {"navigate": path},
1116
+ {"wait_for_selector": "body"},
1117
+ {"screenshot": "count"}
1090
1118
  ]))
1091
1119
 
1092
- console.print(f"✅ Element count retrieved")
1120
+ # Extract element data
1121
+ comprehensive_data = results.get('comprehensive_data', {})
1122
+ dom_analysis = comprehensive_data.get('dom_analysis', {})
1123
+ elements = dom_analysis.get('elements', [])
1124
+
1125
+ # Count matching elements
1126
+ matching_count = sum(1 for element in elements if _element_matches_selector(element, selector))
1127
+
1128
+ if matching_count == 0:
1129
+ console.print(f"[yellow]⚠️ No elements found matching: {selector}[/yellow]")
1130
+ console.print(f"💡 Total elements on page: {len(elements)}")
1131
+ else:
1132
+ console.print(f"[bold green]✅ Found {matching_count} element(s) matching: {selector}[/bold green]")
1133
+ console.print(f"💡 Total elements on page: {len(elements)}")
1093
1134
 
1094
1135
  except Exception as e:
1095
1136
  console.print(f"[red]❌ Count failed: {e}[/red]")
1137
+ import traceback
1138
+ console.print(traceback.format_exc())
1096
1139
 
1097
1140
  @main.command()
1098
1141
  @click.option('--click', '-c', multiple=True)
@@ -131,6 +131,10 @@ class BrowserController:
131
131
  self.context = await self.browser.new_context(**context_config)
132
132
  self.page = await self.context.new_page()
133
133
 
134
+ # Note: We do NOT block tracking scripts by default
135
+ # CursorFlow philosophy: "Capture reality, not fiction"
136
+ # Blocking scripts would alter the actual page behavior we're measuring
137
+
134
138
  # v2.0 Enhancement: Initialize Error Context Collector
135
139
  self.error_context_collector = ErrorContextCollector(self.page, self.logger)
136
140
 
@@ -357,8 +361,9 @@ class BrowserController:
357
361
  self.logger.info(f"Navigating to: {url}")
358
362
 
359
363
  # Navigate and wait
364
+ # Use 'load' instead of 'networkidle' to avoid timeout on pages with tracking scripts
360
365
  if wait_for_load:
361
- await self.page.goto(url, wait_until="networkidle", timeout=30000)
366
+ await self.page.goto(url, wait_until="load", timeout=30000)
362
367
  else:
363
368
  await self.page.goto(url, timeout=30000)
364
369
 
@@ -170,7 +170,12 @@ class MockupComparator:
170
170
  # Save comparison report
171
171
  report_path = self.artifacts_base / "mockup_comparisons" / f"{comparison_name}.json"
172
172
  with open(report_path, 'w') as f:
173
- json.dump(comparison_report, f, indent=2, default=str)
173
+ # Custom JSON encoder to handle numpy booleans/integers
174
+ def json_serializer(obj):
175
+ if hasattr(obj, 'item'): # numpy types
176
+ return obj.item()
177
+ return str(obj)
178
+ json.dump(comparison_report, f, indent=2, default=json_serializer)
174
179
 
175
180
  self.logger.info(f"Mockup comparison completed: {comparison_name}")
176
181
  return comparison_report
@@ -1194,11 +1199,11 @@ class MockupComparator:
1194
1199
  improvement = improved_similarity - baseline_similarity
1195
1200
 
1196
1201
  return {
1197
- "baseline_similarity": baseline_similarity,
1198
- "improved_similarity": improved_similarity,
1199
- "improvement": improvement,
1200
- "improvement_percentage": round(improvement, 2),
1201
- "is_improvement": improvement > 0
1202
+ "baseline_similarity": float(baseline_similarity),
1203
+ "improved_similarity": float(improved_similarity),
1204
+ "improvement": float(improvement),
1205
+ "improvement_percentage": round(float(improvement), 2),
1206
+ "is_improvement": bool(improvement > 0) # Convert to Python bool
1202
1207
  }
1203
1208
 
1204
1209
  except Exception as e:
@@ -1219,10 +1224,10 @@ class MockupComparator:
1219
1224
  avg_similarity = sum(similarities) / len(similarities) if similarities else 0
1220
1225
 
1221
1226
  return {
1222
- "average_similarity": round(avg_similarity, 2),
1227
+ "average_similarity": round(float(avg_similarity), 2),
1223
1228
  "viewports_tested": len(comparison_results),
1224
1229
  "best_viewport_match": max(comparison_results, key=lambda x: x.get("visual_diff", {}).get("similarity_score", 0)),
1225
- "needs_improvement": avg_similarity < 80 # Threshold for "good enough"
1230
+ "needs_improvement": bool(avg_similarity < 80) # Convert numpy.bool_ to Python bool
1226
1231
  }
1227
1232
 
1228
1233
  def _generate_improvement_recommendations(self, comparison_results: List[Dict]) -> List[Dict]:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cursorflow"
7
- version = "2.4.1"
7
+ version = "2.4.3"
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.4.1"
75
+ python_version = "2.4.3"
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