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.
- {cursorflow-2.4.1 → cursorflow-2.4.3}/PKG-INFO +1 -1
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/cli.py +55 -12
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/browser_controller.py +6 -1
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/mockup_comparator.py +13 -8
- {cursorflow-2.4.1 → cursorflow-2.4.3}/pyproject.toml +2 -2
- {cursorflow-2.4.1 → cursorflow-2.4.3}/LICENSE +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/MANIFEST.in +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/README.md +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/__init__.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/auto_init.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/auto_updater.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/action_validator.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/agent.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/auth_handler.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/browser_engine.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/config_validator.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/css_iterator.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/cursor_integration.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/cursorflow.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/error_context_collector.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/error_correlator.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/event_correlator.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/file_change_monitor.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/hmr_detector.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/log_collector.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/log_monitor.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/persistent_session.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/report_generator.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/core/trace_manager.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/install_cursorflow_rules.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/log_sources/local_file.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/log_sources/ssh_remote.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/post_install.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/rules/__init__.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/rules/cursorflow-installation.mdc +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/rules/cursorflow-usage.mdc +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow/updater.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/cursorflow.egg-info/SOURCES.txt +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/docs/user/USAGE_GUIDE.md +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/comprehensive_screenshot_example.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/element_inspection_example.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/element_measurement_example.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/enhanced_screenshot_example.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/hot_reload_css_iteration.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/mockup_comparison_example.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/opensas_example.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/react_example.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/responsive_testing_example.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/examples/v2_comprehensive_demo.py +0 -0
- {cursorflow-2.4.1 → cursorflow-2.4.3}/setup.cfg +0 -0
- {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.
|
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
|
-
|
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
|
-
|
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
|
-
|
923
|
-
|
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
|
-
|
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
|
-
#
|
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
|
-
|
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="
|
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
|
-
|
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 #
|
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.
|
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.
|
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
|
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
|