cursorflow 2.4.1__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 CHANGED
@@ -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]:
@@ -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
@@ -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=sukvrOvphTfXZSbFUAqePmp11SKlV2Vu6SL4hgrf20A,62877
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=0jjYEzAr1qtuzHAhBn3Jff8FZrMBPx8gF0mDv7QWcgQ,146683
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=VLfEEaTgbcY0oTb-bhBD2uTbXGjbnOV7LXNVvXpWMrM,64695
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.1.dist-info/licenses/LICENSE,sha256=e4QbjAsj3bW-xgQOvQelr8sGLYDoqc48k6cKgCr_pBU,1080
34
- cursorflow-2.4.1.dist-info/METADATA,sha256=E4HcwQv4wmoLS6kCTazQRdEcJHM3GCVmDafHxKyG2ME,14793
35
- cursorflow-2.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
36
- cursorflow-2.4.1.dist-info/entry_points.txt,sha256=-Ed_n4Uff7wClEtWS-Py6xmQabecB9f0QAOjX0w7ljA,51
37
- cursorflow-2.4.1.dist-info/top_level.txt,sha256=t1UZwRyZP4u-ng2CEcNHmk_ZT4ibQxoihB2IjTF7ovc,11
38
- cursorflow-2.4.1.dist-info/RECORD,,
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,,