cursorflow 1.3.6__py3-none-any.whl → 2.0.0__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/core/browser_controller.py +1367 -80
- cursorflow/core/error_context_collector.py +590 -0
- cursorflow/core/hmr_detector.py +439 -0
- cursorflow/core/mockup_comparator.py +32 -6
- cursorflow/core/trace_manager.py +209 -0
- cursorflow/log_sources/local_file.py +5 -1
- cursorflow/log_sources/ssh_remote.py +7 -2
- cursorflow-2.0.0.dist-info/METADATA +293 -0
- {cursorflow-1.3.6.dist-info → cursorflow-2.0.0.dist-info}/RECORD +13 -10
- cursorflow-1.3.6.dist-info/METADATA +0 -247
- {cursorflow-1.3.6.dist-info → cursorflow-2.0.0.dist-info}/WHEEL +0 -0
- {cursorflow-1.3.6.dist-info → cursorflow-2.0.0.dist-info}/entry_points.txt +0 -0
- {cursorflow-1.3.6.dist-info → cursorflow-2.0.0.dist-info}/licenses/LICENSE +0 -0
- {cursorflow-1.3.6.dist-info → cursorflow-2.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,209 @@
|
|
1
|
+
"""
|
2
|
+
Trace Manager for CursorFlow v2.0
|
3
|
+
|
4
|
+
Manages Playwright trace file recording for complete interaction history.
|
5
|
+
Pure observation - records everything without modifying application behavior.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import asyncio
|
9
|
+
import time
|
10
|
+
import logging
|
11
|
+
from typing import Optional, Dict, Any
|
12
|
+
from pathlib import Path
|
13
|
+
from playwright.async_api import BrowserContext
|
14
|
+
|
15
|
+
|
16
|
+
class TraceManager:
|
17
|
+
"""
|
18
|
+
Manages Playwright trace recording for comprehensive debugging data
|
19
|
+
|
20
|
+
Provides complete interaction history, screenshots, and network activity
|
21
|
+
in Playwright's native trace format for maximum debugging capability.
|
22
|
+
"""
|
23
|
+
|
24
|
+
def __init__(self, artifacts_base: Path):
|
25
|
+
"""
|
26
|
+
Initialize trace manager
|
27
|
+
|
28
|
+
Args:
|
29
|
+
artifacts_base: Base directory for storing trace files
|
30
|
+
"""
|
31
|
+
self.artifacts_base = artifacts_base
|
32
|
+
self.traces_dir = artifacts_base / "traces"
|
33
|
+
self.traces_dir.mkdir(parents=True, exist_ok=True)
|
34
|
+
|
35
|
+
self.current_trace_path: Optional[Path] = None
|
36
|
+
self.is_recording = False
|
37
|
+
self.session_id: Optional[str] = None
|
38
|
+
|
39
|
+
self.logger = logging.getLogger(__name__)
|
40
|
+
|
41
|
+
async def start_trace(self, context: BrowserContext, session_id: str) -> str:
|
42
|
+
"""
|
43
|
+
Start Playwright trace recording
|
44
|
+
|
45
|
+
Args:
|
46
|
+
context: Browser context to record
|
47
|
+
session_id: Unique session identifier
|
48
|
+
|
49
|
+
Returns:
|
50
|
+
Path where trace will be saved
|
51
|
+
"""
|
52
|
+
try:
|
53
|
+
self.session_id = session_id
|
54
|
+
self.current_trace_path = self.traces_dir / f"{session_id}.zip"
|
55
|
+
|
56
|
+
# Start comprehensive trace recording
|
57
|
+
await context.tracing.start(
|
58
|
+
screenshots=True, # Capture screenshots at each action
|
59
|
+
snapshots=True, # Capture DOM snapshots
|
60
|
+
sources=True, # Include source code context
|
61
|
+
title=f"CursorFlow Session {session_id}"
|
62
|
+
)
|
63
|
+
|
64
|
+
self.is_recording = True
|
65
|
+
self.logger.info(f"Started trace recording: {self.current_trace_path}")
|
66
|
+
|
67
|
+
return str(self.current_trace_path)
|
68
|
+
|
69
|
+
except Exception as e:
|
70
|
+
self.logger.error(f"Failed to start trace recording: {e}")
|
71
|
+
self.is_recording = False
|
72
|
+
raise
|
73
|
+
|
74
|
+
async def stop_trace(self, context: BrowserContext) -> Optional[str]:
|
75
|
+
"""
|
76
|
+
Stop trace recording and save file
|
77
|
+
|
78
|
+
Args:
|
79
|
+
context: Browser context being recorded
|
80
|
+
|
81
|
+
Returns:
|
82
|
+
Path to saved trace file, or None if recording wasn't active
|
83
|
+
"""
|
84
|
+
if not self.is_recording or not self.current_trace_path:
|
85
|
+
return None
|
86
|
+
|
87
|
+
try:
|
88
|
+
await context.tracing.stop(path=str(self.current_trace_path))
|
89
|
+
|
90
|
+
trace_path = str(self.current_trace_path)
|
91
|
+
file_size = self.current_trace_path.stat().st_size if self.current_trace_path.exists() else 0
|
92
|
+
|
93
|
+
self.logger.info(f"Trace recording saved: {trace_path} ({file_size:,} bytes)")
|
94
|
+
|
95
|
+
# Reset state
|
96
|
+
self.is_recording = False
|
97
|
+
self.current_trace_path = None
|
98
|
+
self.session_id = None
|
99
|
+
|
100
|
+
return trace_path
|
101
|
+
|
102
|
+
except Exception as e:
|
103
|
+
self.logger.error(f"Failed to stop trace recording: {e}")
|
104
|
+
self.is_recording = False
|
105
|
+
return None
|
106
|
+
|
107
|
+
async def stop_trace_on_error(self, context: BrowserContext, error: Exception) -> Optional[str]:
|
108
|
+
"""
|
109
|
+
Stop trace recording when an error occurs, with error context
|
110
|
+
|
111
|
+
Args:
|
112
|
+
context: Browser context being recorded
|
113
|
+
error: The error that occurred
|
114
|
+
|
115
|
+
Returns:
|
116
|
+
Path to saved trace file with error context
|
117
|
+
"""
|
118
|
+
if not self.is_recording or not self.current_trace_path:
|
119
|
+
return None
|
120
|
+
|
121
|
+
try:
|
122
|
+
# Add error context to trace filename
|
123
|
+
error_trace_path = self.traces_dir / f"{self.session_id}_ERROR_{type(error).__name__}.zip"
|
124
|
+
|
125
|
+
await context.tracing.stop(path=str(error_trace_path))
|
126
|
+
|
127
|
+
file_size = error_trace_path.stat().st_size if error_trace_path.exists() else 0
|
128
|
+
|
129
|
+
self.logger.info(f"Error trace saved: {error_trace_path} ({file_size:,} bytes)")
|
130
|
+
self.logger.info(f"View trace: playwright show-trace {error_trace_path}")
|
131
|
+
|
132
|
+
# Reset state
|
133
|
+
self.is_recording = False
|
134
|
+
self.current_trace_path = None
|
135
|
+
self.session_id = None
|
136
|
+
|
137
|
+
return str(error_trace_path)
|
138
|
+
|
139
|
+
except Exception as trace_error:
|
140
|
+
self.logger.error(f"Failed to save error trace: {trace_error}")
|
141
|
+
self.is_recording = False
|
142
|
+
return None
|
143
|
+
|
144
|
+
def get_trace_info(self) -> Dict[str, Any]:
|
145
|
+
"""
|
146
|
+
Get current trace recording information
|
147
|
+
|
148
|
+
Returns:
|
149
|
+
Dictionary with trace status and metadata
|
150
|
+
"""
|
151
|
+
return {
|
152
|
+
"is_recording": self.is_recording,
|
153
|
+
"session_id": self.session_id,
|
154
|
+
"trace_path": str(self.current_trace_path) if self.current_trace_path else None,
|
155
|
+
"traces_directory": str(self.traces_dir),
|
156
|
+
"total_traces": len(list(self.traces_dir.glob("*.zip")))
|
157
|
+
}
|
158
|
+
|
159
|
+
def cleanup_old_traces(self, max_traces: int = 50) -> int:
|
160
|
+
"""
|
161
|
+
Clean up old trace files to prevent disk space issues
|
162
|
+
|
163
|
+
Args:
|
164
|
+
max_traces: Maximum number of trace files to keep
|
165
|
+
|
166
|
+
Returns:
|
167
|
+
Number of traces deleted
|
168
|
+
"""
|
169
|
+
try:
|
170
|
+
trace_files = sorted(
|
171
|
+
self.traces_dir.glob("*.zip"),
|
172
|
+
key=lambda p: p.stat().st_mtime,
|
173
|
+
reverse=True # Newest first
|
174
|
+
)
|
175
|
+
|
176
|
+
if len(trace_files) <= max_traces:
|
177
|
+
return 0
|
178
|
+
|
179
|
+
# Delete oldest traces
|
180
|
+
traces_to_delete = trace_files[max_traces:]
|
181
|
+
deleted_count = 0
|
182
|
+
|
183
|
+
for trace_file in traces_to_delete:
|
184
|
+
try:
|
185
|
+
trace_file.unlink()
|
186
|
+
deleted_count += 1
|
187
|
+
except Exception as e:
|
188
|
+
self.logger.warning(f"Failed to delete old trace {trace_file}: {e}")
|
189
|
+
|
190
|
+
if deleted_count > 0:
|
191
|
+
self.logger.info(f"Cleaned up {deleted_count} old trace files")
|
192
|
+
|
193
|
+
return deleted_count
|
194
|
+
|
195
|
+
except Exception as e:
|
196
|
+
self.logger.error(f"Trace cleanup failed: {e}")
|
197
|
+
return 0
|
198
|
+
|
199
|
+
def get_viewing_instructions(self, trace_path: str) -> str:
|
200
|
+
"""
|
201
|
+
Get instructions for viewing a trace file
|
202
|
+
|
203
|
+
Args:
|
204
|
+
trace_path: Path to the trace file
|
205
|
+
|
206
|
+
Returns:
|
207
|
+
Command to view the trace
|
208
|
+
"""
|
209
|
+
return f"playwright show-trace {trace_path}"
|
@@ -98,7 +98,11 @@ class LocalFileLogSource:
|
|
98
98
|
return True
|
99
99
|
|
100
100
|
except Exception as e:
|
101
|
-
|
101
|
+
# Log as debug instead of error for non-critical issues
|
102
|
+
if "No such file or directory" in str(e) or "Permission denied" in str(e):
|
103
|
+
self.logger.debug(f"Non-critical log file issue for {log_name}: {e}")
|
104
|
+
else:
|
105
|
+
self.logger.error(f"Failed to start tail for {log_name}: {e}")
|
102
106
|
return False
|
103
107
|
|
104
108
|
def _read_tail_output(self, log_name: str, log_path: str, process: subprocess.Popen):
|
@@ -10,8 +10,9 @@ import threading
|
|
10
10
|
import queue
|
11
11
|
import time
|
12
12
|
import logging
|
13
|
+
import re
|
13
14
|
from typing import Dict, List, Optional
|
14
|
-
from datetime import datetime
|
15
|
+
from datetime import datetime, timedelta
|
15
16
|
|
16
17
|
class SSHRemoteLogSource:
|
17
18
|
"""Remote log monitoring via SSH"""
|
@@ -89,7 +90,11 @@ class SSHRemoteLogSource:
|
|
89
90
|
return result == 'test'
|
90
91
|
|
91
92
|
except Exception as e:
|
92
|
-
|
93
|
+
# Log SSH connection issues as debug for non-critical cases
|
94
|
+
if "Connection refused" in str(e) or "timeout" in str(e).lower():
|
95
|
+
self.logger.debug(f"SSH connection issue (may be expected): {e}")
|
96
|
+
else:
|
97
|
+
self.logger.error(f"SSH connection test failed: {e}")
|
93
98
|
return False
|
94
99
|
|
95
100
|
def _monitor_single_log(self, log_name: str, log_path: str):
|
@@ -0,0 +1,293 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: cursorflow
|
3
|
+
Version: 2.0.0
|
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
|
+
Author-email: GeekWarrior Development <rbush@cooltheory.com>
|
6
|
+
License-Expression: MIT
|
7
|
+
Project-URL: Homepage, https://github.com/haley-marketing-group/cursorflow
|
8
|
+
Project-URL: Documentation, https://cursorflow.readthedocs.io
|
9
|
+
Project-URL: Repository, https://github.com/haley-marketing-group/cursorflow
|
10
|
+
Keywords: ui-testing,automation,cursor,ai,web-testing,css-iteration,hot-reload,hmr,element-intelligence,page-analysis,error-context
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
12
|
+
Classifier: Intended Audience :: Developers
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
19
|
+
Classifier: Topic :: Software Development :: Testing
|
20
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
21
|
+
Classifier: Framework :: AsyncIO
|
22
|
+
Requires-Python: >=3.8
|
23
|
+
Description-Content-Type: text/markdown
|
24
|
+
License-File: LICENSE
|
25
|
+
Requires-Dist: playwright>=1.40.0
|
26
|
+
Requires-Dist: paramiko>=3.3.1
|
27
|
+
Requires-Dist: pyyaml>=6.0.1
|
28
|
+
Requires-Dist: asyncio-mqtt>=0.11.1
|
29
|
+
Requires-Dist: click>=8.1.7
|
30
|
+
Requires-Dist: rich>=13.6.0
|
31
|
+
Requires-Dist: jinja2>=3.1.2
|
32
|
+
Requires-Dist: python-dateutil>=2.8.2
|
33
|
+
Requires-Dist: watchdog>=3.0.0
|
34
|
+
Requires-Dist: docker>=6.1.3
|
35
|
+
Requires-Dist: pillow>=10.0.0
|
36
|
+
Requires-Dist: numpy>=1.24.0
|
37
|
+
Requires-Dist: websockets>=11.0.0
|
38
|
+
Provides-Extra: dev
|
39
|
+
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
40
|
+
Requires-Dist: pytest-asyncio>=0.21.1; extra == "dev"
|
41
|
+
Requires-Dist: black>=23.9.1; extra == "dev"
|
42
|
+
Requires-Dist: flake8>=6.1.0; extra == "dev"
|
43
|
+
Requires-Dist: mypy>=1.6.1; extra == "dev"
|
44
|
+
Dynamic: license-file
|
45
|
+
|
46
|
+
# CursorFlow
|
47
|
+
|
48
|
+
**Complete page intelligence for AI-driven development**
|
49
|
+
|
50
|
+
CursorFlow captures comprehensive data from web applications - DOM structure, CSS properties, network activity, console logs, and performance metrics - enabling AI agents like Cursor to make intelligent decisions about UI improvements and debugging.
|
51
|
+
|
52
|
+
## 🎯 What CursorFlow Does
|
53
|
+
|
54
|
+
**Data Collection, Not Analysis** - We gather structured data, AI makes the decisions.
|
55
|
+
|
56
|
+
### **📊 Complete Page Intelligence**
|
57
|
+
Every screenshot captures everything:
|
58
|
+
- **DOM**: All elements with 7 selector strategies each
|
59
|
+
- **Network**: All requests, responses, and complete response bodies
|
60
|
+
- **Console**: All logs, errors, and smart error correlation
|
61
|
+
- **Performance**: Load times, memory usage, with reliability indicators
|
62
|
+
- **Visual**: Screenshots with pixel-perfect comparisons
|
63
|
+
- **Fonts**: Loading status, performance, and usage analysis
|
64
|
+
- **Animations**: Active animations and transitions tracking
|
65
|
+
- **Resources**: Complete resource loading analysis
|
66
|
+
- **Storage**: localStorage, sessionStorage, cookies, IndexedDB state
|
67
|
+
|
68
|
+
### **🔄 Rapid Iteration Support**
|
69
|
+
- **Hot Reload Intelligence** with framework auto-detection (Vite, Webpack, Next.js, Parcel, Laravel Mix)
|
70
|
+
- **Mockup comparison** with enhanced DOM and CSS analysis
|
71
|
+
- **Hot reload integration** for instant, perfectly-timed CSS testing
|
72
|
+
- **Persistent sessions** that survive code changes
|
73
|
+
- **Universal framework support** (React, Vue, PHP, Perl, anything)
|
74
|
+
|
75
|
+
### **🤖 AI-First Design**
|
76
|
+
All data structured for AI consumption:
|
77
|
+
- Consistent JSON format across all features
|
78
|
+
- **Multi-selector element identification** for robust automation
|
79
|
+
- **Accessibility-aware** element analysis
|
80
|
+
- Error correlation with **smart screenshot deduplication**
|
81
|
+
- Performance insights with **reliability metadata**
|
82
|
+
- **HMR event correlation** for CSS change tracking
|
83
|
+
|
84
|
+
## 🚀 Quick Start
|
85
|
+
|
86
|
+
```bash
|
87
|
+
# Install CursorFlow
|
88
|
+
pip install cursorflow
|
89
|
+
|
90
|
+
# Test with complete intelligence
|
91
|
+
cursorflow test --base-url http://localhost:3000 --actions '[
|
92
|
+
{"navigate": "/dashboard"},
|
93
|
+
{"wait_for": "#main-content"},
|
94
|
+
{"screenshot": "dashboard-loaded"}
|
95
|
+
]'
|
96
|
+
|
97
|
+
# HMR-powered CSS iteration
|
98
|
+
cursorflow iterate-mockup https://mockup.com/design \
|
99
|
+
--base-url http://localhost:5173 \
|
100
|
+
--css-improvements '[
|
101
|
+
{"name": "fix-spacing", "css": ".container { gap: 2rem; }"}
|
102
|
+
]'
|
103
|
+
```
|
104
|
+
|
105
|
+
## 💻 Usage Examples
|
106
|
+
|
107
|
+
### **Hot Reload Intelligence**
|
108
|
+
```python
|
109
|
+
from cursorflow import CursorFlow
|
110
|
+
|
111
|
+
async def hmr_workflow():
|
112
|
+
flow = CursorFlow("http://localhost:5173", {"headless": False})
|
113
|
+
|
114
|
+
# Start HMR monitoring (auto-detects Vite/Webpack/Next.js)
|
115
|
+
await flow.browser.start_hmr_monitoring()
|
116
|
+
|
117
|
+
# Take baseline
|
118
|
+
await flow.execute_and_collect([
|
119
|
+
{"navigate": "/app"},
|
120
|
+
{"screenshot": "baseline"}
|
121
|
+
])
|
122
|
+
|
123
|
+
# Wait for CSS changes with perfect timing
|
124
|
+
hmr_event = await flow.browser.wait_for_css_update()
|
125
|
+
print(f"🔥 {hmr_event['framework']} CSS update detected!")
|
126
|
+
|
127
|
+
# Capture immediately after change
|
128
|
+
await flow.execute_and_collect([
|
129
|
+
{"screenshot": "updated"}
|
130
|
+
])
|
131
|
+
```
|
132
|
+
|
133
|
+
### **Advanced Element Analysis**
|
134
|
+
```python
|
135
|
+
# Get comprehensive element data
|
136
|
+
results = await flow.execute_and_collect([
|
137
|
+
{"navigate": "/form"},
|
138
|
+
{"screenshot": "form-analysis"}
|
139
|
+
])
|
140
|
+
|
141
|
+
# Access enhanced element data
|
142
|
+
for element in results['artifacts']['screenshots'][0]['dom_analysis']['elements']:
|
143
|
+
print(f"Element: {element['selector']}")
|
144
|
+
print(f" 7 Selectors: {list(element['selectors'].keys())}")
|
145
|
+
print(f" Accessible: {element['accessibility']['role']}")
|
146
|
+
print(f" Interactive: {element['accessibility']['interactive']}")
|
147
|
+
print(f" Visible: {element['visual_context']['visibility']['is_visible']}")
|
148
|
+
```
|
149
|
+
|
150
|
+
### **Comprehensive Page Intelligence**
|
151
|
+
```python
|
152
|
+
# Get complete page analysis
|
153
|
+
screenshot = results['artifacts']['screenshots'][0]
|
154
|
+
|
155
|
+
# Complete Intelligence
|
156
|
+
print(f"Fonts loaded: {screenshot['font_status']['loadedFonts']}")
|
157
|
+
print(f"Animations running: {screenshot['animation_status']['runningAnimations']}")
|
158
|
+
print(f"Resources: {screenshot['resource_status']['totalResources']}")
|
159
|
+
print(f"Storage items: {screenshot['storage_status']['localStorage']['itemCount']}")
|
160
|
+
```
|
161
|
+
|
162
|
+
### **Smart Error Diagnostics**
|
163
|
+
```python
|
164
|
+
# Enhanced error context with deduplication
|
165
|
+
error_context = await flow.browser.capture_interaction_error_context(
|
166
|
+
action_description="Submit form",
|
167
|
+
error_details={"type": "validation_error"}
|
168
|
+
)
|
169
|
+
|
170
|
+
print(f"Screenshot: {error_context['screenshot_info']['path']}")
|
171
|
+
print(f"Reused: {error_context['screenshot_info']['is_reused']}") # Smart deduplication
|
172
|
+
print(f"Context: {len(error_context['recent_actions'])} recent actions")
|
173
|
+
```
|
174
|
+
|
175
|
+
## 🔧 CLI Commands
|
176
|
+
|
177
|
+
### **Universal Testing with Complete Intelligence**
|
178
|
+
```bash
|
179
|
+
# Simple page test with full intelligence
|
180
|
+
cursorflow test --base-url http://localhost:3000 --path "/dashboard"
|
181
|
+
|
182
|
+
# Complex interaction test
|
183
|
+
cursorflow test --base-url http://localhost:3000 --actions '[
|
184
|
+
{"navigate": "/login"},
|
185
|
+
{"fill": {"selector": "#email", "value": "test@example.com"}},
|
186
|
+
{"click": "#login-btn"},
|
187
|
+
{"wait_for": ".dashboard"},
|
188
|
+
{"screenshot": "logged-in"}
|
189
|
+
]'
|
190
|
+
```
|
191
|
+
|
192
|
+
### **HMR-Powered CSS Iteration**
|
193
|
+
```bash
|
194
|
+
# Perfect CSS iteration with HMR intelligence
|
195
|
+
cursorflow iterate-mockup https://mockup.com/design \
|
196
|
+
--base-url http://localhost:5173 \
|
197
|
+
--css-improvements '[
|
198
|
+
{"name": "improve-spacing", "css": ".container { gap: 2rem; }"},
|
199
|
+
{"name": "enhance-colors", "css": ".button { background: #007bff; }"}
|
200
|
+
]'
|
201
|
+
```
|
202
|
+
|
203
|
+
### **Enhanced Design Comparison**
|
204
|
+
```bash
|
205
|
+
# Compare with comprehensive intelligence
|
206
|
+
cursorflow compare-mockup https://mockup.com/design \
|
207
|
+
--base-url http://localhost:3000 \
|
208
|
+
--mockup-actions '[{"navigate": "/"}]' \
|
209
|
+
--implementation-actions '[{"navigate": "/dashboard"}]'
|
210
|
+
```
|
211
|
+
|
212
|
+
## 🧠 AI Integration
|
213
|
+
|
214
|
+
### **Cursor Rules (Auto-Install)**
|
215
|
+
```bash
|
216
|
+
# Install AI assistance rules
|
217
|
+
cursorflow install-rules
|
218
|
+
```
|
219
|
+
|
220
|
+
CursorFlow includes comprehensive rules that teach Cursor:
|
221
|
+
- **When to use HMR intelligence** for CSS iteration
|
222
|
+
- **How to analyze multi-selector element data**
|
223
|
+
- **Best practices for comprehensive page analysis**
|
224
|
+
- **Error debugging with smart context collection**
|
225
|
+
|
226
|
+
### **Structured Data for AI**
|
227
|
+
Every CursorFlow operation returns **perfectly structured JSON** optimized for AI analysis:
|
228
|
+
|
229
|
+
```json
|
230
|
+
{
|
231
|
+
"artifacts": {
|
232
|
+
"screenshots": [{
|
233
|
+
"path": ".cursorflow/artifacts/screenshots/dashboard_123.png",
|
234
|
+
"dom_analysis": {
|
235
|
+
"elements": [...], // 7 selectors + accessibility per element
|
236
|
+
"pageStructure": {...}, // Enhanced page analysis
|
237
|
+
"analysisVersion": "2.0" // Version tracking
|
238
|
+
},
|
239
|
+
"font_status": {...}, // Font loading intelligence
|
240
|
+
"animation_status": {...}, // Animation tracking
|
241
|
+
"resource_status": {...}, // Resource analysis
|
242
|
+
"storage_status": {...}, // Storage state
|
243
|
+
"hmr_status": {...} // HMR event data
|
244
|
+
}]
|
245
|
+
}
|
246
|
+
}
|
247
|
+
```
|
248
|
+
|
249
|
+
## 🌟 Framework Support
|
250
|
+
|
251
|
+
**HMR Auto-Detection:**
|
252
|
+
- ✅ **Vite** (port 5173, WebSocket `/__vite_hmr`)
|
253
|
+
- ✅ **Webpack Dev Server** (port 3000, WebSocket `/sockjs-node`)
|
254
|
+
- ✅ **Next.js** (port 3000, WebSocket `/_next/webpack-hmr`)
|
255
|
+
- ✅ **Parcel** (port 1234, WebSocket `/hmr`)
|
256
|
+
- ✅ **Laravel Mix** (port 3000, WebSocket `/browser-sync/socket.io`)
|
257
|
+
|
258
|
+
**Universal Compatibility:**
|
259
|
+
- Works with **any web application** regardless of framework
|
260
|
+
- **Framework-agnostic** core operations
|
261
|
+
- **Smart adaptation** to different development environments
|
262
|
+
|
263
|
+
## 📖 Documentation
|
264
|
+
|
265
|
+
- **[Complete User Manual](docs/USER_MANUAL.md)** - Full feature guide
|
266
|
+
- **[Examples](examples/)** - Practical usage examples
|
267
|
+
- **[API Reference](docs/api/)** - Complete Python API documentation
|
268
|
+
|
269
|
+
## 🚀 Why CursorFlow?
|
270
|
+
|
271
|
+
### **For Developers:**
|
272
|
+
- **Faster CSS iteration** with HMR precision timing
|
273
|
+
- **Complete element intelligence** with multi-selector strategies
|
274
|
+
- **Full page visibility** with comprehensive analysis
|
275
|
+
- **Smart error debugging** with rich context collection
|
276
|
+
|
277
|
+
### **For AI Agents:**
|
278
|
+
- **Perfect structured data** for intelligent decision making
|
279
|
+
- **Multi-selector reliability** for robust automation
|
280
|
+
- **Accessibility awareness** for inclusive development
|
281
|
+
- **HMR correlation** for understanding change impact
|
282
|
+
|
283
|
+
### **For Teams:**
|
284
|
+
- **Framework agnostic** - works with any web technology
|
285
|
+
- **Production ready** - handles real-world complexity
|
286
|
+
- **Comprehensive testing** - covers all aspects of web apps
|
287
|
+
- **AI-first design** - built for autonomous development
|
288
|
+
|
289
|
+
---
|
290
|
+
|
291
|
+
**Complete page intelligence for AI-driven development with CursorFlow**
|
292
|
+
|
293
|
+
*Hot reload precision • Advanced element analysis • Smart error diagnostics • Comprehensive page intelligence*
|
@@ -5,27 +5,30 @@ cursorflow/install_cursorflow_rules.py,sha256=ny4c-S1O-V2sITunZO2kk6sCf1yec42UJO
|
|
5
5
|
cursorflow/updater.py,sha256=pvbSZgg6hgWZBE5AAUPppS5Yzv0yNMp2X_CL2GALg_w,18783
|
6
6
|
cursorflow/core/agent.py,sha256=f3lecgEzDRDdGTVccAtorpLGfNJJ49bbsQAmgr0vNGg,10136
|
7
7
|
cursorflow/core/auth_handler.py,sha256=oRafO6ZdxoHryBIvHsrNV8TECed4GXpJsdEiH0KdPPk,17149
|
8
|
-
cursorflow/core/browser_controller.py,sha256=
|
8
|
+
cursorflow/core/browser_controller.py,sha256=OII52LBgN97-G-6mPCiqbFGbHnU9KtHaYB0qeylqo2U,125963
|
9
9
|
cursorflow/core/browser_engine.py,sha256=Glq8U_bXRkO2Yal0nku7Z2wKwOftY4So2XN4oy56WLo,13732
|
10
10
|
cursorflow/core/css_iterator.py,sha256=whLCIwbHZEWaH1HCbmqhNX5zrh_fL-r3hsxKjYsukcE,16478
|
11
11
|
cursorflow/core/cursor_integration.py,sha256=MAeHjXYeqzaXnhskqkTDB-n5ixIHqapGe93X0lLKhws,67501
|
12
12
|
cursorflow/core/cursorflow.py,sha256=GohWXvCLTsIIxI2UBRkFPM3yptbPNw4wI1vxKRPPMd0,31816
|
13
|
+
cursorflow/core/error_context_collector.py,sha256=so-aveqwb6_vRDbtKR2ln8_F84aaVIceNi1UHsaVPgc,26196
|
13
14
|
cursorflow/core/error_correlator.py,sha256=g6YaIF2yFXUDrTuWHCyuES6K0696H8LDWmXH1qI8ddA,13367
|
14
15
|
cursorflow/core/event_correlator.py,sha256=lCzXFnii17AQt3rOVOclez_AnjvBCF_2ZlnFG0mIN6c,7808
|
15
16
|
cursorflow/core/file_change_monitor.py,sha256=tl_ZdsGW8LZBTImniD-lqaGgNb9dYjlDsP2XmevE0xk,21258
|
17
|
+
cursorflow/core/hmr_detector.py,sha256=IrGYhXIeTBukffRXF74SW45cB_Im0cmq8RxxjtSz-2w,17431
|
16
18
|
cursorflow/core/log_collector.py,sha256=vZ2Slm6C_OOi68xROWpXPSZqzzQAWK0sk5xEybGlA4w,14217
|
17
19
|
cursorflow/core/log_monitor.py,sha256=pONMu_JHEnT0T62OA5KRZ4nClzKgNpifPyrfN5w_RM8,6704
|
18
|
-
cursorflow/core/mockup_comparator.py,sha256=
|
20
|
+
cursorflow/core/mockup_comparator.py,sha256=VLfEEaTgbcY0oTb-bhBD2uTbXGjbnOV7LXNVvXpWMrM,64695
|
19
21
|
cursorflow/core/persistent_session.py,sha256=FsEHj4wKkycmdp6PFRHv3g333Y74yqra0x_qhUTQpik,36075
|
20
22
|
cursorflow/core/report_generator.py,sha256=-vosfyrnfVyWDbAIMlMurl90xOXqBae8d6aLd9sEqiY,10113
|
21
|
-
cursorflow/
|
22
|
-
cursorflow/log_sources/
|
23
|
+
cursorflow/core/trace_manager.py,sha256=Jj9ultZrL1atiZXfcRVI6ynCnnfqZM-X0_taxt-llJ0,7189
|
24
|
+
cursorflow/log_sources/local_file.py,sha256=Hn3hDQjAqgNBQN8b5AbC6IQAzgY_ekLgePwDuq9wBlA,7101
|
25
|
+
cursorflow/log_sources/ssh_remote.py,sha256=zSnX8mpa5G86UDWEm3_FqYwo1PjBW67C1LPkJ5Ta_ho,7482
|
23
26
|
cursorflow/rules/__init__.py,sha256=gPcA-IkhXj03sl7cvZV0wwo7CtEkcyuKs4y0F5oQbqE,458
|
24
27
|
cursorflow/rules/cursorflow-installation.mdc,sha256=Nnu7PuP5nGD6hGAV_x2SX5Y2_uPz3oNA5XUjNJBFC1M,6985
|
25
28
|
cursorflow/rules/cursorflow-usage.mdc,sha256=Zv0TWuo7S3iJHq8R6oBaHRI3V6h-T81pdb7vi-b8NoU,14157
|
26
|
-
cursorflow-
|
27
|
-
cursorflow-
|
28
|
-
cursorflow-
|
29
|
-
cursorflow-
|
30
|
-
cursorflow-
|
31
|
-
cursorflow-
|
29
|
+
cursorflow-2.0.0.dist-info/licenses/LICENSE,sha256=e4QbjAsj3bW-xgQOvQelr8sGLYDoqc48k6cKgCr_pBU,1080
|
30
|
+
cursorflow-2.0.0.dist-info/METADATA,sha256=umhLvqBVKOkvvJ0as3gfKDGmd-KW2POSW8c1nHovBAk,10656
|
31
|
+
cursorflow-2.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
32
|
+
cursorflow-2.0.0.dist-info/entry_points.txt,sha256=-Ed_n4Uff7wClEtWS-Py6xmQabecB9f0QAOjX0w7ljA,51
|
33
|
+
cursorflow-2.0.0.dist-info/top_level.txt,sha256=t1UZwRyZP4u-ng2CEcNHmk_ZT4ibQxoihB2IjTF7ovc,11
|
34
|
+
cursorflow-2.0.0.dist-info/RECORD,,
|