cursorflow 2.4.2__py3-none-any.whl → 2.4.3__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 +11 -12
- cursorflow/core/browser_controller.py +5 -31
- cursorflow/core/mockup_comparator.py +13 -8
- {cursorflow-2.4.2.dist-info → cursorflow-2.4.3.dist-info}/METADATA +1 -1
- {cursorflow-2.4.2.dist-info → cursorflow-2.4.3.dist-info}/RECORD +9 -9
- {cursorflow-2.4.2.dist-info → cursorflow-2.4.3.dist-info}/WHEEL +0 -0
- {cursorflow-2.4.2.dist-info → cursorflow-2.4.3.dist-info}/entry_points.txt +0 -0
- {cursorflow-2.4.2.dist-info → cursorflow-2.4.3.dist-info}/licenses/LICENSE +0 -0
- {cursorflow-2.4.2.dist-info → cursorflow-2.4.3.dist-info}/top_level.txt +0 -0
cursorflow/cli.py
CHANGED
@@ -357,13 +357,11 @@ def test(base_url, path, actions, output, logs, config, verbose, headless, timeo
|
|
357
357
|
help='JSON array of viewports to test: [{"width": 1440, "height": 900, "name": "desktop"}]')
|
358
358
|
@click.option('--diff-threshold', '-t', type=float, default=0.1,
|
359
359
|
help='Visual difference threshold (0.0-1.0)')
|
360
|
-
@click.option('--block-tracking', is_flag=True,
|
361
|
-
help='Block tracking scripts (Google Analytics, Facebook Pixel, etc.) to prevent timeout')
|
362
360
|
@click.option('--output', '-o', default='mockup_comparison_results.json',
|
363
361
|
help='Output file for comparison results')
|
364
362
|
@click.option('--verbose', is_flag=True,
|
365
363
|
help='Verbose output')
|
366
|
-
def compare_mockup(mockup_url, base_url, mockup_actions, implementation_actions, viewports, diff_threshold,
|
364
|
+
def compare_mockup(mockup_url, base_url, mockup_actions, implementation_actions, viewports, diff_threshold, output, verbose):
|
367
365
|
"""Compare mockup design to work-in-progress implementation"""
|
368
366
|
|
369
367
|
console.print(f"🎨 Comparing mockup [blue]{mockup_url}[/blue] to implementation [blue]{base_url}[/blue]")
|
@@ -407,16 +405,10 @@ def compare_mockup(mockup_url, base_url, mockup_actions, implementation_actions,
|
|
407
405
|
try:
|
408
406
|
from .core.cursorflow import CursorFlow
|
409
407
|
|
410
|
-
# Configure browser with tracking blocking if requested
|
411
|
-
browser_config = {'headless': True}
|
412
|
-
if block_tracking:
|
413
|
-
browser_config['block_tracking'] = True
|
414
|
-
console.print("🚫 Blocking tracking scripts (Google Analytics, Facebook Pixel, etc.)")
|
415
|
-
|
416
408
|
flow = CursorFlow(
|
417
409
|
base_url=base_url,
|
418
410
|
log_config={'source': 'local', 'paths': ['logs/app.log']},
|
419
|
-
browser_config=
|
411
|
+
browser_config={'headless': True}
|
420
412
|
)
|
421
413
|
except Exception as e:
|
422
414
|
console.print(f"[red]Error initializing CursorFlow: {e}[/red]")
|
@@ -449,9 +441,16 @@ def compare_mockup(mockup_url, base_url, mockup_actions, implementation_actions,
|
|
449
441
|
for i, rec in enumerate(recommendations[:3]): # Show first 3
|
450
442
|
console.print(f" {i+1}. {rec.get('description', 'No description')}")
|
451
443
|
|
452
|
-
# Save results
|
444
|
+
# Save results with numpy type handling
|
453
445
|
with open(output, 'w') as f:
|
454
|
-
|
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)
|
455
454
|
|
456
455
|
console.print(f"💾 Full results saved to: [cyan]{output}[/cyan]")
|
457
456
|
console.print(f"📁 Visual diffs stored in: [cyan].cursorflow/artifacts/[/cyan]")
|
@@ -131,9 +131,9 @@ 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
|
-
#
|
135
|
-
|
136
|
-
|
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
137
|
|
138
138
|
# v2.0 Enhancement: Initialize Error Context Collector
|
139
139
|
self.error_context_collector = ErrorContextCollector(self.page, self.logger)
|
@@ -173,33 +173,6 @@ class BrowserController:
|
|
173
173
|
|
174
174
|
raise
|
175
175
|
|
176
|
-
async def _setup_tracking_blocker(self):
|
177
|
-
"""Block common tracking scripts to prevent networkidle timeout"""
|
178
|
-
tracking_patterns = [
|
179
|
-
"*google-analytics.com/*",
|
180
|
-
"*googletagmanager.com/*",
|
181
|
-
"*facebook.com/tr/*",
|
182
|
-
"*facebook.net/*",
|
183
|
-
"*doubleclick.net/*",
|
184
|
-
"*analytics.google.com/*",
|
185
|
-
"*hotjar.com/*",
|
186
|
-
"*mixpanel.com/*",
|
187
|
-
"*segment.com/*",
|
188
|
-
"*googleadservices.com/*",
|
189
|
-
"*connect.facebook.net/*",
|
190
|
-
"*/analytics/*",
|
191
|
-
"*/tracking/*"
|
192
|
-
]
|
193
|
-
|
194
|
-
async def block_tracking(route):
|
195
|
-
"""Block tracking request"""
|
196
|
-
await route.abort()
|
197
|
-
|
198
|
-
for pattern in tracking_patterns:
|
199
|
-
await self.page.route(pattern, block_tracking)
|
200
|
-
|
201
|
-
self.logger.info("🚫 Tracking scripts blocked")
|
202
|
-
|
203
176
|
async def _setup_event_listeners(self):
|
204
177
|
"""Set up universal event listeners for any framework"""
|
205
178
|
|
@@ -388,8 +361,9 @@ class BrowserController:
|
|
388
361
|
self.logger.info(f"Navigating to: {url}")
|
389
362
|
|
390
363
|
# Navigate and wait
|
364
|
+
# Use 'load' instead of 'networkidle' to avoid timeout on pages with tracking scripts
|
391
365
|
if wait_for_load:
|
392
|
-
await self.page.goto(url, wait_until="
|
366
|
+
await self.page.goto(url, wait_until="load", timeout=30000)
|
393
367
|
else:
|
394
368
|
await self.page.goto(url, timeout=30000)
|
395
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]:
|
@@ -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
|
@@ -1,14 +1,14 @@
|
|
1
1
|
cursorflow/__init__.py,sha256=2V9xzG2tYxVWOTmSw2v9Jdbr7lSrMi_y2SMUMuNZdvw,2990
|
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=CzvxsXYt-cHImGDgnzO1cVjUE819fX6UrILMTGL4v3U,65084
|
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=sTEHdBAFCy-gxwAXCMPA9cyMU3uu0gE-hXfjMJqQnnQ,147003
|
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
|
@@ -21,7 +21,7 @@ cursorflow/core/file_change_monitor.py,sha256=tl_ZdsGW8LZBTImniD-lqaGgNb9dYjlDsP
|
|
21
21
|
cursorflow/core/hmr_detector.py,sha256=IrGYhXIeTBukffRXF74SW45cB_Im0cmq8RxxjtSz-2w,17431
|
22
22
|
cursorflow/core/log_collector.py,sha256=CYh41SLDI_t-hgzJqG3fTrSTDhEPFDktjO_mOQwucnE,15198
|
23
23
|
cursorflow/core/log_monitor.py,sha256=pONMu_JHEnT0T62OA5KRZ4nClzKgNpifPyrfN5w_RM8,6704
|
24
|
-
cursorflow/core/mockup_comparator.py,sha256=
|
24
|
+
cursorflow/core/mockup_comparator.py,sha256=Xg6_LGfPxTAaEf5eVdrBBtq8NVtBhy-C8wd-96w3WwY,65059
|
25
25
|
cursorflow/core/persistent_session.py,sha256=FsEHj4wKkycmdp6PFRHv3g333Y74yqra0x_qhUTQpik,36075
|
26
26
|
cursorflow/core/report_generator.py,sha256=-vosfyrnfVyWDbAIMlMurl90xOXqBae8d6aLd9sEqiY,10113
|
27
27
|
cursorflow/core/trace_manager.py,sha256=Jj9ultZrL1atiZXfcRVI6ynCnnfqZM-X0_taxt-llJ0,7189
|
@@ -30,9 +30,9 @@ cursorflow/log_sources/ssh_remote.py,sha256=_Kwh0bhRpKgq-0c98oaX2hN6h9cT-wCHlqY5
|
|
30
30
|
cursorflow/rules/__init__.py,sha256=gPcA-IkhXj03sl7cvZV0wwo7CtEkcyuKs4y0F5oQbqE,458
|
31
31
|
cursorflow/rules/cursorflow-installation.mdc,sha256=D55pzzDPAVVbE3gAtKPUGoT-2fvB-FI2l6yrTdzUIEo,10208
|
32
32
|
cursorflow/rules/cursorflow-usage.mdc,sha256=8TUeQ1hq2fTlgPqUBYOVBXrdEN0BR0Xp0d_1L-eUsME,23150
|
33
|
-
cursorflow-2.4.
|
34
|
-
cursorflow-2.4.
|
35
|
-
cursorflow-2.4.
|
36
|
-
cursorflow-2.4.
|
37
|
-
cursorflow-2.4.
|
38
|
-
cursorflow-2.4.
|
33
|
+
cursorflow-2.4.3.dist-info/licenses/LICENSE,sha256=e4QbjAsj3bW-xgQOvQelr8sGLYDoqc48k6cKgCr_pBU,1080
|
34
|
+
cursorflow-2.4.3.dist-info/METADATA,sha256=kyrYszlZJXJSSjvt4wdASU4onxYp3vq3MoFVtv49rdQ,14793
|
35
|
+
cursorflow-2.4.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
36
|
+
cursorflow-2.4.3.dist-info/entry_points.txt,sha256=-Ed_n4Uff7wClEtWS-Py6xmQabecB9f0QAOjX0w7ljA,51
|
37
|
+
cursorflow-2.4.3.dist-info/top_level.txt,sha256=t1UZwRyZP4u-ng2CEcNHmk_ZT4ibQxoihB2IjTF7ovc,11
|
38
|
+
cursorflow-2.4.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|