cursorflow 2.7.1__py3-none-any.whl → 2.7.2__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
@@ -1151,6 +1151,8 @@ def inspect(base_url, path, selector, verbose):
1151
1151
  results = asyncio.run(flow.execute_and_collect([
1152
1152
  {"navigate": path},
1153
1153
  {"wait_for_selector": "body"},
1154
+ {"wait_for_load_state": "networkidle"}, # Wait for dynamic content
1155
+ {"wait_for_timeout": 1000}, # Additional buffer for JS rendering (1s)
1154
1156
  {"screenshot": "inspection"}
1155
1157
  ]))
1156
1158
 
@@ -1200,7 +1202,7 @@ def inspect(base_url, path, selector, verbose):
1200
1202
  console.print(f"Classes: [blue].{classes}[/blue]")
1201
1203
 
1202
1204
  # Selectors
1203
- unique_selector = element.get('uniqueSelector', 'N/A')
1205
+ unique_selector = escape(str(element.get('uniqueSelector', 'N/A')))
1204
1206
  console.print(f"Unique: [cyan]{unique_selector}[/cyan]")
1205
1207
 
1206
1208
  # Dimensions
@@ -1216,20 +1218,22 @@ def inspect(base_url, path, selector, verbose):
1216
1218
  console.print(f"\n🎨 Key CSS Properties:")
1217
1219
 
1218
1220
  # Layout
1219
- display = computed.get('display', 'N/A')
1220
- position = computed.get('position', 'N/A')
1221
+ display = escape(str(computed.get('display', 'N/A')))
1222
+ position = escape(str(computed.get('position', 'N/A')))
1221
1223
  console.print(f" display: {display}")
1222
1224
  console.print(f" position: {position}")
1223
1225
 
1224
1226
  # Flexbox
1225
1227
  if 'flex' in computed:
1226
- console.print(f" flex: {computed.get('flex', 'N/A')}")
1228
+ flex_value = escape(str(computed.get('flex', 'N/A')))
1229
+ console.print(f" flex: {flex_value}")
1227
1230
  if 'flexBasis' in computed:
1228
- console.print(f" flex-basis: {computed.get('flexBasis', 'N/A')}")
1231
+ flex_basis = escape(str(computed.get('flexBasis', 'N/A')))
1232
+ console.print(f" flex-basis: {flex_basis}")
1229
1233
 
1230
1234
  # Dimensions
1231
- width = computed.get('width', 'N/A')
1232
- height = computed.get('height', 'N/A')
1235
+ width = escape(str(computed.get('width', 'N/A')))
1236
+ height = escape(str(computed.get('height', 'N/A')))
1233
1237
  console.print(f" width: {width}")
1234
1238
  console.print(f" height: {height}")
1235
1239
 
@@ -1237,20 +1241,23 @@ def inspect(base_url, path, selector, verbose):
1237
1241
  margin = computed.get('margin', 'N/A')
1238
1242
  padding = computed.get('padding', 'N/A')
1239
1243
  if margin != 'N/A':
1244
+ margin = escape(str(margin))
1240
1245
  console.print(f" margin: {margin}")
1241
1246
  if padding != 'N/A':
1247
+ padding = escape(str(padding))
1242
1248
  console.print(f" padding: {padding}")
1243
1249
 
1244
1250
  # Show all styles in verbose mode
1245
1251
  if verbose:
1246
1252
  console.print(f"\n📋 All Computed Styles:")
1247
1253
  for prop, value in sorted(computed.items())[:30]: # Limit to 30
1248
- console.print(f" {prop}: {value}")
1254
+ safe_value = escape(str(value))
1255
+ console.print(f" {prop}: {safe_value}")
1249
1256
 
1250
1257
  # Accessibility info
1251
1258
  accessibility = element.get('accessibility', {})
1252
1259
  if accessibility:
1253
- role = accessibility.get('role', 'N/A')
1260
+ role = escape(str(accessibility.get('role', 'N/A')))
1254
1261
  is_interactive = accessibility.get('isInteractive', False)
1255
1262
  console.print(f"\n♿ Accessibility:")
1256
1263
  console.print(f" Role: {role}")
@@ -1293,8 +1300,9 @@ def inspect(base_url, path, selector, verbose):
1293
1300
 
1294
1301
  except Exception as e:
1295
1302
  console.print(f"[red]❌ Inspection failed: {escape(str(e))}[/red]")
1296
- import traceback
1297
- console.print(traceback.format_exc())
1303
+ if verbose:
1304
+ import traceback
1305
+ console.print(escape(traceback.format_exc()))
1298
1306
 
1299
1307
  def _element_matches_selector(element: Dict, selector: str) -> bool:
1300
1308
  """Check if element matches the given selector"""
@@ -146,31 +146,28 @@ class OutputManager:
146
146
 
147
147
  def _extract_summary(self, results: Dict) -> Dict:
148
148
  """Extract high-level summary data"""
149
- comprehensive = results.get('comprehensive_data', {})
149
+ # Load comprehensive data from disk if available
150
+ comprehensive = self._load_comprehensive_data(results)
150
151
  artifacts = results.get('artifacts', {})
151
152
 
152
- # Count errors
153
+ # Count errors from comprehensive_data
153
154
  error_count = 0
154
155
  warning_count = 0
155
- console_screenshots = artifacts.get('console_errors', [])
156
- for screenshot in console_screenshots:
157
- if isinstance(screenshot, dict):
158
- console_data = screenshot.get('console_data', {})
159
- errors = console_data.get('errors', {})
160
- error_count += len(errors.get('logs', []))
161
- warnings = console_data.get('warnings', {})
162
- warning_count += len(warnings.get('logs', []))
156
+ if comprehensive:
157
+ console_data = comprehensive.get('console_data', {})
158
+ all_console_logs = console_data.get('all_console_logs', [])
159
+ error_count = len([log for log in all_console_logs if log.get('type') == 'error'])
160
+ warning_count = len([log for log in all_console_logs if log.get('type') == 'warning'])
163
161
 
164
- # Count network requests
162
+ # Count network requests from comprehensive_data
165
163
  network_count = 0
166
164
  failed_network_count = 0
167
- for screenshot in artifacts.get('screenshots', []):
168
- if isinstance(screenshot, dict):
169
- network_data = screenshot.get('network_data', {})
170
- requests = network_data.get('requests', [])
171
- network_count += len(requests)
172
- failed_requests = network_data.get('failed_requests', {})
173
- failed_network_count += len(failed_requests.get('requests', []))
165
+ if comprehensive:
166
+ network_data = comprehensive.get('network_data', {})
167
+ all_network_events = network_data.get('all_network_events', [])
168
+ network_count = len(all_network_events)
169
+ # Count failures (4xx, 5xx)
170
+ failed_network_count = len([req for req in all_network_events if req.get('status', 0) >= 400])
174
171
 
175
172
  # Count DOM elements
176
173
  dom_element_count = 0
@@ -202,26 +199,50 @@ class OutputManager:
202
199
 
203
200
  def _extract_errors(self, results: Dict) -> Dict:
204
201
  """Extract all error data with context"""
205
- artifacts = results.get('artifacts', {})
206
202
  errors = []
207
203
 
208
- # Collect errors from all screenshots
209
- for screenshot in artifacts.get('screenshots', []):
210
- if isinstance(screenshot, dict):
211
- console_data = screenshot.get('console_data', {})
212
- error_logs = console_data.get('errors', {}).get('logs', [])
213
-
214
- for error in error_logs:
204
+ # Load comprehensive data from disk if available
205
+ comprehensive_data = self._load_comprehensive_data(results)
206
+
207
+ if comprehensive_data:
208
+ console_data = comprehensive_data.get('console_data', {})
209
+ all_console_logs = console_data.get('all_console_logs', [])
210
+
211
+ # Filter for errors
212
+ for log in all_console_logs:
213
+ if log.get('type') == 'error':
214
+ # Extract location info if present
215
+ location = log.get('location', {})
215
216
  errors.append({
216
- "message": error.get('message', ''),
217
- "source": error.get('source', ''),
218
- "line": error.get('line', 0),
219
- "column": error.get('column', 0),
220
- "stack_trace": error.get('stack_trace', ''),
221
- "timestamp": screenshot.get('timestamp', 0),
222
- "screenshot_name": screenshot.get('name', 'unknown'),
223
- "url": screenshot.get('url', '')
217
+ "message": log.get('text', ''),
218
+ "source": location.get('url', ''),
219
+ "line": location.get('lineNumber', 0),
220
+ "column": location.get('columnNumber', 0),
221
+ "stack_trace": log.get('stackTrace', {}).get('callFrames', []),
222
+ "timestamp": log.get('timestamp', 0),
223
+ "screenshot_name": 'comprehensive',
224
+ "url": location.get('url', '')
224
225
  })
226
+ else:
227
+ # Fallback: Collect errors from screenshot artifacts (old structure)
228
+ # Only if comprehensive_data not available
229
+ artifacts = results.get('artifacts', {})
230
+ for screenshot in artifacts.get('screenshots', []):
231
+ if isinstance(screenshot, dict):
232
+ console_data = screenshot.get('console_data', {})
233
+ error_logs = console_data.get('errors', {}).get('logs', [])
234
+
235
+ for error in error_logs:
236
+ errors.append({
237
+ "message": error.get('message', ''),
238
+ "source": error.get('source', ''),
239
+ "line": error.get('line', 0),
240
+ "column": error.get('column', 0),
241
+ "stack_trace": error.get('stack_trace', ''),
242
+ "timestamp": screenshot.get('timestamp', 0),
243
+ "screenshot_name": screenshot.get('name', 'unknown'),
244
+ "url": screenshot.get('url', '')
245
+ })
225
246
 
226
247
  # Organize by error type
227
248
  error_types = {}
@@ -243,29 +264,55 @@ class OutputManager:
243
264
 
244
265
  def _extract_network(self, results: Dict) -> Dict:
245
266
  """Extract network request/response data"""
246
- artifacts = results.get('artifacts', {})
247
267
  all_requests = []
248
268
  failed_requests = []
249
269
 
250
- for screenshot in artifacts.get('screenshots', []):
251
- if isinstance(screenshot, dict):
252
- network_data = screenshot.get('network_data', {})
253
- requests = network_data.get('requests', [])
254
-
255
- for request in requests:
256
- all_requests.append({
257
- **request,
258
- "screenshot_name": screenshot.get('name', 'unknown'),
259
- "timestamp": screenshot.get('timestamp', 0)
260
- })
270
+ # Load comprehensive data from disk if available
271
+ comprehensive_data = self._load_comprehensive_data(results)
272
+
273
+ if comprehensive_data:
274
+ network_data = comprehensive_data.get('network_data', {})
275
+ all_network_events = network_data.get('all_network_events', [])
276
+
277
+ # Add all network events and identify failures
278
+ for event in all_network_events:
279
+ request_data = {
280
+ "url": event.get('url', ''),
281
+ "method": event.get('method', 'GET'),
282
+ "status_code": event.get('status', 0),
283
+ "timestamp": event.get('timestamp', 0),
284
+ "timing": event.get('timing', {}),
285
+ "screenshot_name": 'comprehensive'
286
+ }
287
+ all_requests.append(request_data)
261
288
 
262
- failed = network_data.get('failed_requests', {}).get('requests', [])
263
- for request in failed:
264
- failed_requests.append({
265
- **request,
266
- "screenshot_name": screenshot.get('name', 'unknown'),
267
- "timestamp": screenshot.get('timestamp', 0)
268
- })
289
+ # Identify failed requests (4xx, 5xx status codes)
290
+ status = event.get('status', 0)
291
+ if status >= 400:
292
+ failed_requests.append(request_data)
293
+ else:
294
+ # Fallback: Collect from screenshot artifacts (old structure)
295
+ # Only if comprehensive_data not available
296
+ artifacts = results.get('artifacts', {})
297
+ for screenshot in artifacts.get('screenshots', []):
298
+ if isinstance(screenshot, dict):
299
+ network_data = screenshot.get('network_data', {})
300
+ requests = network_data.get('requests', [])
301
+
302
+ for request in requests:
303
+ all_requests.append({
304
+ **request,
305
+ "screenshot_name": screenshot.get('name', 'unknown'),
306
+ "timestamp": screenshot.get('timestamp', 0)
307
+ })
308
+
309
+ failed = network_data.get('failed_requests', {}).get('requests', [])
310
+ for request in failed:
311
+ failed_requests.append({
312
+ **request,
313
+ "screenshot_name": screenshot.get('name', 'unknown'),
314
+ "timestamp": screenshot.get('timestamp', 0)
315
+ })
269
316
 
270
317
  # Organize by status code
271
318
  by_status_code = {}
@@ -288,24 +335,42 @@ class OutputManager:
288
335
 
289
336
  def _extract_console(self, results: Dict) -> Dict:
290
337
  """Extract all console messages"""
291
- artifacts = results.get('artifacts', {})
292
338
  all_messages = []
293
339
 
294
- for screenshot in artifacts.get('screenshots', []):
295
- if isinstance(screenshot, dict):
296
- console_data = screenshot.get('console_data', {})
297
-
298
- # Collect all message types
299
- for msg_type in ['errors', 'warnings', 'logs', 'info']:
300
- messages = console_data.get(msg_type, {}).get('logs', [])
301
- for msg in messages:
302
- all_messages.append({
303
- "type": msg_type,
304
- "message": msg.get('message', ''),
305
- "source": msg.get('source', ''),
306
- "timestamp": screenshot.get('timestamp', 0),
307
- "screenshot_name": screenshot.get('name', 'unknown')
308
- })
340
+ # Load comprehensive data from disk if available
341
+ comprehensive_data = self._load_comprehensive_data(results)
342
+
343
+ if comprehensive_data:
344
+ console_data = comprehensive_data.get('console_data', {})
345
+ all_console_logs = console_data.get('all_console_logs', [])
346
+
347
+ for log in all_console_logs:
348
+ all_messages.append({
349
+ "type": log.get('type', 'log'),
350
+ "message": log.get('text', ''),
351
+ "source": log.get('location', {}).get('url', ''),
352
+ "timestamp": log.get('timestamp', 0),
353
+ "screenshot_name": 'comprehensive'
354
+ })
355
+ else:
356
+ # Fallback: Collect from screenshot artifacts (old structure)
357
+ # Only if comprehensive_data not available
358
+ artifacts = results.get('artifacts', {})
359
+ for screenshot in artifacts.get('screenshots', []):
360
+ if isinstance(screenshot, dict):
361
+ console_data = screenshot.get('console_data', {})
362
+
363
+ # Collect all message types
364
+ for msg_type in ['errors', 'warnings', 'logs', 'info']:
365
+ messages = console_data.get(msg_type, {}).get('logs', [])
366
+ for msg in messages:
367
+ all_messages.append({
368
+ "type": msg_type,
369
+ "message": msg.get('message', ''),
370
+ "source": msg.get('source', ''),
371
+ "timestamp": screenshot.get('timestamp', 0),
372
+ "screenshot_name": screenshot.get('name', 'unknown')
373
+ })
309
374
 
310
375
  # Organize by type
311
376
  by_type = {}
@@ -335,9 +400,22 @@ class OutputManager:
335
400
 
336
401
  def _extract_performance(self, results: Dict) -> Dict:
337
402
  """Extract performance metrics"""
338
- artifacts = results.get('artifacts', {})
339
403
  performance_data = []
340
404
 
405
+ # Load comprehensive data from disk if available
406
+ comprehensive = self._load_comprehensive_data(results)
407
+
408
+ if comprehensive and 'performance_data' in comprehensive:
409
+ perf = comprehensive.get('performance_data', {})
410
+ if perf:
411
+ performance_data.append({
412
+ "screenshot_name": 'comprehensive',
413
+ "timestamp": results.get('execution_time', 0),
414
+ "metrics": perf
415
+ })
416
+
417
+ # Fallback: from screenshot artifacts
418
+ artifacts = results.get('artifacts', {})
341
419
  for screenshot in artifacts.get('screenshots', []):
342
420
  if isinstance(screenshot, dict):
343
421
  perf = screenshot.get('performance_data', {})
@@ -512,6 +590,44 @@ class OutputManager:
512
590
  "min_memory_usage": min(memory_usage) if memory_usage else 0
513
591
  }
514
592
 
593
+ def _load_comprehensive_data(self, results: Dict) -> Dict:
594
+ """Load comprehensive data from disk or from results dict"""
595
+ # First try to get from results (if already loaded)
596
+ comprehensive = results.get('comprehensive_data', {})
597
+ if comprehensive:
598
+ return comprehensive
599
+
600
+ # Try to load from disk via screenshot artifacts
601
+ artifacts = results.get('artifacts', {})
602
+ screenshots = artifacts.get('screenshots', [])
603
+
604
+ if screenshots:
605
+ last_screenshot = screenshots[-1]
606
+ # Check if comprehensive_data_path is set
607
+ if isinstance(last_screenshot, dict) and 'comprehensive_data_path' in last_screenshot:
608
+ comp_path = Path(last_screenshot['comprehensive_data_path'])
609
+ if comp_path.exists():
610
+ try:
611
+ with open(comp_path, 'r', encoding='utf-8') as f:
612
+ return json.load(f)
613
+ except Exception as e:
614
+ self.logger.warning(f"Could not load comprehensive data from {comp_path}: {e}")
615
+
616
+ # Try to find comprehensive data file by naming convention
617
+ if isinstance(last_screenshot, dict) and 'path' in last_screenshot:
618
+ screenshot_path = Path(last_screenshot['path'])
619
+ if screenshot_path.exists():
620
+ # Look for companion comprehensive data file
621
+ comp_path = screenshot_path.parent / f"{screenshot_path.stem}_comprehensive_data.json"
622
+ if comp_path.exists():
623
+ try:
624
+ with open(comp_path, 'r', encoding='utf-8') as f:
625
+ return json.load(f)
626
+ except Exception as e:
627
+ self.logger.warning(f"Could not load comprehensive data from {comp_path}: {e}")
628
+
629
+ return {}
630
+
515
631
  def _write_json(self, path: Path, data: Dict):
516
632
  """Write JSON data to file with proper formatting"""
517
633
  with open(path, 'w', encoding='utf-8') as f:
@@ -317,11 +317,8 @@ class QueryEngine:
317
317
 
318
318
  # Filter failed requests only
319
319
  if 'failed' in filters and filters['failed']:
320
- failed_reqs = network.get('failed_requests', [])
321
- filtered_requests = [
322
- req for req in all_requests
323
- if req.get('url') in [f.get('url') for f in failed_reqs]
324
- ]
320
+ # Use failed_requests array directly (already filtered)
321
+ filtered_requests = network.get('failed_requests', [])
325
322
 
326
323
  # Phase 1: Enhanced network filtering
327
324
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cursorflow
3
- Version: 2.7.1
3
+ Version: 2.7.2
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,7 +1,7 @@
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=2jPCIBTGdN7ZFFf7HpWNHdtdEZ27vJSx5P_t4L7Y1Z8,79716
4
+ cursorflow/cli.py,sha256=jU-jEqFZUWngSYv-sNPxF7nn_hYZ4-K0TJsqucRPMmM,80268
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
@@ -24,9 +24,9 @@ cursorflow/core/json_utils.py,sha256=ofqRP1twDSHQx-SERgLTO5y2ZXkoirsEw8OOiJkGh2w
24
24
  cursorflow/core/log_collector.py,sha256=CYh41SLDI_t-hgzJqG3fTrSTDhEPFDktjO_mOQwucnE,15198
25
25
  cursorflow/core/log_monitor.py,sha256=pONMu_JHEnT0T62OA5KRZ4nClzKgNpifPyrfN5w_RM8,6704
26
26
  cursorflow/core/mockup_comparator.py,sha256=ttcXdueZz9dwcUGBQ2sft4i66zRdkZkFPu41s6JlEwU,63472
27
- cursorflow/core/output_manager.py,sha256=fyIhxoJO1Hps8HgGMEekzfSfFqcO4iy7YliXes2nvxI,22054
27
+ cursorflow/core/output_manager.py,sha256=PT73Awq4htYVwbBN3EadXGvuy3Wreip0Y35sCg7Pz5s,28013
28
28
  cursorflow/core/persistent_session.py,sha256=FsEHj4wKkycmdp6PFRHv3g333Y74yqra0x_qhUTQpik,36075
29
- cursorflow/core/query_engine.py,sha256=kNqnVk_QxJXkhF2p9TM3L6J8w7pBVob1wEo-vPfSrP4,54075
29
+ cursorflow/core/query_engine.py,sha256=138mEdd0D5w2zzYrcBEegDcxbY1hS9hio-U121Tj2wA,53984
30
30
  cursorflow/core/report_generator.py,sha256=-vosfyrnfVyWDbAIMlMurl90xOXqBae8d6aLd9sEqiY,10113
31
31
  cursorflow/core/trace_manager.py,sha256=Jj9ultZrL1atiZXfcRVI6ynCnnfqZM-X0_taxt-llJ0,7189
32
32
  cursorflow/log_sources/local_file.py,sha256=GVnhsaifIdc41twXwbxRM9-fBeRDsknDpk5IEGulnhQ,8318
@@ -34,9 +34,9 @@ cursorflow/log_sources/ssh_remote.py,sha256=_Kwh0bhRpKgq-0c98oaX2hN6h9cT-wCHlqY5
34
34
  cursorflow/rules/__init__.py,sha256=gPcA-IkhXj03sl7cvZV0wwo7CtEkcyuKs4y0F5oQbqE,458
35
35
  cursorflow/rules/cursorflow-installation.mdc,sha256=D55pzzDPAVVbE3gAtKPUGoT-2fvB-FI2l6yrTdzUIEo,10208
36
36
  cursorflow/rules/cursorflow-usage.mdc,sha256=e5l9sKtrkphRSOfqZTN7fvTvzPNoBAuVyCxFpAJ4uYY,31403
37
- cursorflow-2.7.1.dist-info/licenses/LICENSE,sha256=e4QbjAsj3bW-xgQOvQelr8sGLYDoqc48k6cKgCr_pBU,1080
38
- cursorflow-2.7.1.dist-info/METADATA,sha256=uRVlMJxjtG1AUAe5Udd5AxUW_As2EVhz9qrhGOVY09E,17538
39
- cursorflow-2.7.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
40
- cursorflow-2.7.1.dist-info/entry_points.txt,sha256=-Ed_n4Uff7wClEtWS-Py6xmQabecB9f0QAOjX0w7ljA,51
41
- cursorflow-2.7.1.dist-info/top_level.txt,sha256=t1UZwRyZP4u-ng2CEcNHmk_ZT4ibQxoihB2IjTF7ovc,11
42
- cursorflow-2.7.1.dist-info/RECORD,,
37
+ cursorflow-2.7.2.dist-info/licenses/LICENSE,sha256=e4QbjAsj3bW-xgQOvQelr8sGLYDoqc48k6cKgCr_pBU,1080
38
+ cursorflow-2.7.2.dist-info/METADATA,sha256=seQbf_TZ742n1ZTROhD8lWvzpor0Fams1xLjoJeRE7Q,17538
39
+ cursorflow-2.7.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
40
+ cursorflow-2.7.2.dist-info/entry_points.txt,sha256=-Ed_n4Uff7wClEtWS-Py6xmQabecB9f0QAOjX0w7ljA,51
41
+ cursorflow-2.7.2.dist-info/top_level.txt,sha256=t1UZwRyZP4u-ng2CEcNHmk_ZT4ibQxoihB2IjTF7ovc,11
42
+ cursorflow-2.7.2.dist-info/RECORD,,