cursorflow 1.3.0__py3-none-any.whl → 1.3.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 +33 -11
- cursorflow/install_cursorflow_rules.py +271 -0
- {cursorflow-1.3.0.dist-info → cursorflow-1.3.2.dist-info}/METADATA +28 -7
- {cursorflow-1.3.0.dist-info → cursorflow-1.3.2.dist-info}/RECORD +8 -7
- {cursorflow-1.3.0.dist-info → cursorflow-1.3.2.dist-info}/WHEEL +0 -0
- {cursorflow-1.3.0.dist-info → cursorflow-1.3.2.dist-info}/entry_points.txt +0 -0
- {cursorflow-1.3.0.dist-info → cursorflow-1.3.2.dist-info}/licenses/LICENSE +0 -0
- {cursorflow-1.3.0.dist-info → cursorflow-1.3.2.dist-info}/top_level.txt +0 -0
cursorflow/cli.py
CHANGED
@@ -26,11 +26,14 @@ def main():
|
|
26
26
|
pass
|
27
27
|
|
28
28
|
@main.command()
|
29
|
-
@click.
|
30
|
-
|
31
|
-
|
29
|
+
@click.option('--base-url', '-u', required=True,
|
30
|
+
help='Base URL for testing (e.g., http://localhost:3000)')
|
31
|
+
@click.option('--path', '-p',
|
32
|
+
help='Simple path to navigate to (e.g., "/dashboard")')
|
32
33
|
@click.option('--actions', '-a',
|
33
34
|
help='JSON file with test actions, or inline JSON string')
|
35
|
+
@click.option('--output', '-o',
|
36
|
+
help='Output file for results (auto-generated if not specified)')
|
34
37
|
@click.option('--logs', '-l',
|
35
38
|
type=click.Choice(['local', 'ssh', 'docker', 'systemd']),
|
36
39
|
default='local',
|
@@ -39,7 +42,11 @@ def main():
|
|
39
42
|
help='Configuration file path')
|
40
43
|
@click.option('--verbose', '-v', is_flag=True,
|
41
44
|
help='Verbose output')
|
42
|
-
|
45
|
+
@click.option('--headless', is_flag=True, default=True,
|
46
|
+
help='Run browser in headless mode')
|
47
|
+
@click.option('--timeout', type=int, default=30,
|
48
|
+
help='Timeout in seconds for actions')
|
49
|
+
def test(base_url, path, actions, output, logs, config, verbose, headless, timeout):
|
43
50
|
"""Test UI flows and interactions with real-time log monitoring"""
|
44
51
|
|
45
52
|
if verbose:
|
@@ -65,14 +72,22 @@ def test(test_name, base_url, actions, logs, config, verbose):
|
|
65
72
|
except Exception as e:
|
66
73
|
console.print(f"[red]❌ Failed to load actions: {e}[/red]")
|
67
74
|
return
|
75
|
+
elif path:
|
76
|
+
# Simple path navigation
|
77
|
+
test_actions = [
|
78
|
+
{"navigate": path},
|
79
|
+
{"wait_for": "body"},
|
80
|
+
{"screenshot": "page_loaded"}
|
81
|
+
]
|
82
|
+
console.print(f"📋 Using simple path navigation to [cyan]{path}[/cyan]")
|
68
83
|
else:
|
69
|
-
# Default actions - just navigate and screenshot
|
84
|
+
# Default actions - just navigate to root and screenshot
|
70
85
|
test_actions = [
|
71
86
|
{"navigate": "/"},
|
72
87
|
{"wait_for": "body"},
|
73
88
|
{"screenshot": "baseline"}
|
74
89
|
]
|
75
|
-
console.print(f"📋 Using default actions (navigate + screenshot)")
|
90
|
+
console.print(f"📋 Using default actions (navigate to root + screenshot)")
|
76
91
|
|
77
92
|
# Load configuration
|
78
93
|
agent_config = {}
|
@@ -80,7 +95,8 @@ def test(test_name, base_url, actions, logs, config, verbose):
|
|
80
95
|
with open(config, 'r') as f:
|
81
96
|
agent_config = json.load(f)
|
82
97
|
|
83
|
-
|
98
|
+
test_description = path if path else "root page"
|
99
|
+
console.print(f"🎯 Testing [bold]{test_description}[/bold] at [blue]{base_url}[/blue]")
|
84
100
|
|
85
101
|
# Initialize CursorFlow (framework-agnostic)
|
86
102
|
try:
|
@@ -88,6 +104,7 @@ def test(test_name, base_url, actions, logs, config, verbose):
|
|
88
104
|
flow = CursorFlow(
|
89
105
|
base_url=base_url,
|
90
106
|
log_config={'source': logs, 'paths': ['logs/app.log']},
|
107
|
+
browser_config={'headless': headless, 'timeout': timeout},
|
91
108
|
**agent_config
|
92
109
|
)
|
93
110
|
except Exception as e:
|
@@ -99,7 +116,7 @@ def test(test_name, base_url, actions, logs, config, verbose):
|
|
99
116
|
console.print(f"🚀 Executing {len(test_actions)} actions...")
|
100
117
|
results = asyncio.run(flow.execute_and_collect(test_actions))
|
101
118
|
|
102
|
-
console.print(f"✅ Test completed: {
|
119
|
+
console.print(f"✅ Test completed: {test_description}")
|
103
120
|
console.print(f"📊 Browser events: {len(results.get('browser_events', []))}")
|
104
121
|
console.print(f"📋 Server logs: {len(results.get('server_logs', []))}")
|
105
122
|
console.print(f"📸 Screenshots: {len(results.get('artifacts', {}).get('screenshots', []))}")
|
@@ -110,11 +127,16 @@ def test(test_name, base_url, actions, logs, config, verbose):
|
|
110
127
|
console.print(f"⏰ Timeline events: {len(timeline)}")
|
111
128
|
|
112
129
|
# Save results to file for Cursor analysis
|
113
|
-
|
114
|
-
|
130
|
+
if not output:
|
131
|
+
# Auto-generate meaningful filename
|
132
|
+
session_id = results.get('session_id', 'unknown')
|
133
|
+
path_part = path.replace('/', '_') if path else 'root'
|
134
|
+
output = f"cursorflow_{path_part}_{session_id}.json"
|
135
|
+
|
136
|
+
with open(output, 'w') as f:
|
115
137
|
json.dump(results, f, indent=2, default=str)
|
116
138
|
|
117
|
-
console.print(f"💾 Full results saved to: [cyan]{
|
139
|
+
console.print(f"💾 Full results saved to: [cyan]{output}[/cyan]")
|
118
140
|
console.print(f"📁 Artifacts stored in: [cyan].cursorflow/artifacts/[/cyan]")
|
119
141
|
|
120
142
|
except Exception as e:
|
@@ -0,0 +1,271 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
CursorFlow Rules Installation Script
|
4
|
+
|
5
|
+
Installs CursorFlow usage rules into a user's project for Cursor AI.
|
6
|
+
Run this in your project directory to enable CursorFlow integration.
|
7
|
+
"""
|
8
|
+
|
9
|
+
import os
|
10
|
+
import shutil
|
11
|
+
import json
|
12
|
+
import datetime
|
13
|
+
from pathlib import Path
|
14
|
+
import argparse
|
15
|
+
|
16
|
+
|
17
|
+
def install_cursorflow_rules(project_dir: str = "."):
|
18
|
+
"""Install CursorFlow rules and configuration in user's project"""
|
19
|
+
|
20
|
+
project_path = Path(project_dir).resolve()
|
21
|
+
print(f"🚀 Installing CursorFlow rules in: {project_path}")
|
22
|
+
|
23
|
+
# Create .cursor directory if it doesn't exist
|
24
|
+
cursor_dir = project_path / ".cursor"
|
25
|
+
cursor_dir.mkdir(exist_ok=True)
|
26
|
+
|
27
|
+
rules_dir = cursor_dir / "rules"
|
28
|
+
rules_dir.mkdir(exist_ok=True)
|
29
|
+
|
30
|
+
print(f"📁 Created Cursor rules directory: {rules_dir}")
|
31
|
+
|
32
|
+
# Find CursorFlow package location
|
33
|
+
try:
|
34
|
+
import cursorflow
|
35
|
+
package_dir = Path(cursorflow.__file__).parent.parent
|
36
|
+
rules_source_dir = package_dir / "rules"
|
37
|
+
except ImportError:
|
38
|
+
# Fallback: look for rules in current directory structure
|
39
|
+
current_dir = Path(__file__).parent
|
40
|
+
rules_source_dir = current_dir.parent / "rules" # Go up one level from cursorflow/ to find rules/
|
41
|
+
|
42
|
+
if not rules_source_dir.exists():
|
43
|
+
print(f"❌ Could not find CursorFlow rules directory at: {rules_source_dir}")
|
44
|
+
return False
|
45
|
+
|
46
|
+
# Copy usage rules (not development rules)
|
47
|
+
usage_rules = [
|
48
|
+
"cursorflow-usage.mdc",
|
49
|
+
"cursorflow-installation.mdc"
|
50
|
+
]
|
51
|
+
|
52
|
+
copied_files = []
|
53
|
+
for rule_file in usage_rules:
|
54
|
+
source_file = rules_source_dir / rule_file
|
55
|
+
target_file = rules_dir / rule_file
|
56
|
+
|
57
|
+
if source_file.exists():
|
58
|
+
shutil.copy2(source_file, target_file)
|
59
|
+
copied_files.append(rule_file)
|
60
|
+
print(f"✅ Installed: {rule_file}")
|
61
|
+
else:
|
62
|
+
print(f"⚠️ Rule file not found: {rule_file}")
|
63
|
+
|
64
|
+
# Create project-specific .gitignore entries
|
65
|
+
create_gitignore_entries(project_path)
|
66
|
+
|
67
|
+
# Create CursorFlow configuration template
|
68
|
+
create_config_template(project_path)
|
69
|
+
|
70
|
+
print(f"\n🎉 CursorFlow rules installation complete!")
|
71
|
+
print(f"📋 Installed {len(copied_files)} rule files:")
|
72
|
+
for file in copied_files:
|
73
|
+
print(f" - {file}")
|
74
|
+
|
75
|
+
# Set up automatic update checking
|
76
|
+
setup_update_checking(project_path)
|
77
|
+
|
78
|
+
print(f"\n📝 Next steps:")
|
79
|
+
print(f" 1. Review cursorflow-config.json and update for your project")
|
80
|
+
print(f" 2. Install CursorFlow: pip install cursorflow")
|
81
|
+
print(f" 3. Install Playwright: playwright install chromium")
|
82
|
+
print(f" 4. Start using CursorFlow for UI testing and CSS iteration!")
|
83
|
+
print(f"\n🔄 Update commands:")
|
84
|
+
print(f" - Check for updates: python -m cursorflow check-updates")
|
85
|
+
print(f" - Update CursorFlow: python -m cursorflow update")
|
86
|
+
print(f" - Install dependencies: python -m cursorflow install-deps")
|
87
|
+
|
88
|
+
return True
|
89
|
+
|
90
|
+
|
91
|
+
def create_gitignore_entries(project_path: Path):
|
92
|
+
"""Add CursorFlow artifacts to .gitignore"""
|
93
|
+
|
94
|
+
gitignore_path = project_path / ".gitignore"
|
95
|
+
|
96
|
+
cursorflow_entries = """
|
97
|
+
# CursorFlow artifacts (UI testing framework)
|
98
|
+
.cursorflow/
|
99
|
+
*.cursorflow.log
|
100
|
+
cursorflow_session_*.json
|
101
|
+
"""
|
102
|
+
|
103
|
+
# Check if entries already exist
|
104
|
+
existing_content = ""
|
105
|
+
if gitignore_path.exists():
|
106
|
+
existing_content = gitignore_path.read_text()
|
107
|
+
|
108
|
+
if ".cursorflow/" not in existing_content:
|
109
|
+
with open(gitignore_path, "a") as f:
|
110
|
+
f.write(cursorflow_entries)
|
111
|
+
print("✅ Added CursorFlow entries to .gitignore")
|
112
|
+
else:
|
113
|
+
print("ℹ️ CursorFlow entries already in .gitignore")
|
114
|
+
|
115
|
+
|
116
|
+
def create_config_template(project_path: Path):
|
117
|
+
"""Create CursorFlow configuration template"""
|
118
|
+
|
119
|
+
config_path = project_path / "cursorflow-config.json"
|
120
|
+
|
121
|
+
if config_path.exists():
|
122
|
+
print("ℹ️ cursorflow-config.json already exists")
|
123
|
+
return
|
124
|
+
|
125
|
+
# Auto-detect project type for better defaults
|
126
|
+
project_type = detect_project_type(project_path)
|
127
|
+
|
128
|
+
config_template = {
|
129
|
+
"base_url": get_default_url(project_type),
|
130
|
+
"logs": get_default_log_config(project_type),
|
131
|
+
"auth": {
|
132
|
+
"method": "form",
|
133
|
+
"username_selector": "#username",
|
134
|
+
"password_selector": "#password",
|
135
|
+
"submit_selector": "#login-button",
|
136
|
+
"session_storage": ".cursorflow/sessions/"
|
137
|
+
},
|
138
|
+
"browser": {
|
139
|
+
"headless": True,
|
140
|
+
"debug_mode": False
|
141
|
+
},
|
142
|
+
"_project_type": project_type,
|
143
|
+
"_cursorflow_version": "1.0.0"
|
144
|
+
}
|
145
|
+
|
146
|
+
import json
|
147
|
+
with open(config_path, "w") as f:
|
148
|
+
json.dump(config_template, f, indent=2)
|
149
|
+
|
150
|
+
print(f"✅ Created configuration template: cursorflow-config.json")
|
151
|
+
print(f" Detected project type: {project_type}")
|
152
|
+
|
153
|
+
|
154
|
+
def detect_project_type(project_path: Path) -> str:
|
155
|
+
"""Detect project type for better defaults"""
|
156
|
+
|
157
|
+
if (project_path / "package.json").exists():
|
158
|
+
package_json = project_path / "package.json"
|
159
|
+
try:
|
160
|
+
import json
|
161
|
+
with open(package_json) as f:
|
162
|
+
package_data = json.load(f)
|
163
|
+
|
164
|
+
dependencies = package_data.get("dependencies", {})
|
165
|
+
dev_dependencies = package_data.get("devDependencies", {})
|
166
|
+
all_deps = {**dependencies, **dev_dependencies}
|
167
|
+
|
168
|
+
if "next" in all_deps:
|
169
|
+
return "nextjs"
|
170
|
+
elif "react" in all_deps:
|
171
|
+
return "react"
|
172
|
+
elif "vue" in all_deps:
|
173
|
+
return "vue"
|
174
|
+
else:
|
175
|
+
return "nodejs"
|
176
|
+
except:
|
177
|
+
return "nodejs"
|
178
|
+
|
179
|
+
elif (project_path / "manage.py").exists():
|
180
|
+
return "django"
|
181
|
+
|
182
|
+
elif (project_path / "composer.json").exists():
|
183
|
+
return "php"
|
184
|
+
|
185
|
+
elif (project_path / "Gemfile").exists():
|
186
|
+
return "rails"
|
187
|
+
|
188
|
+
elif any((project_path / f).exists() for f in ["*.pl", "*.pm"]):
|
189
|
+
return "perl"
|
190
|
+
|
191
|
+
else:
|
192
|
+
return "generic"
|
193
|
+
|
194
|
+
|
195
|
+
def get_default_url(project_type: str) -> str:
|
196
|
+
"""Get default development server URL"""
|
197
|
+
|
198
|
+
defaults = {
|
199
|
+
"nextjs": "http://localhost:3000",
|
200
|
+
"react": "http://localhost:3000",
|
201
|
+
"vue": "http://localhost:8080",
|
202
|
+
"nodejs": "http://localhost:3000",
|
203
|
+
"django": "http://localhost:8000",
|
204
|
+
"php": "http://localhost:8080",
|
205
|
+
"rails": "http://localhost:3000",
|
206
|
+
"perl": "http://localhost:8080",
|
207
|
+
"generic": "http://localhost:3000"
|
208
|
+
}
|
209
|
+
|
210
|
+
return defaults.get(project_type, "http://localhost:3000")
|
211
|
+
|
212
|
+
|
213
|
+
def get_default_log_config(project_type: str) -> dict:
|
214
|
+
"""Get default log configuration"""
|
215
|
+
|
216
|
+
log_configs = {
|
217
|
+
"nextjs": {"source": "local", "paths": [".next/trace.log", "logs/app.log"]},
|
218
|
+
"react": {"source": "local", "paths": ["logs/app.log", "console.log"]},
|
219
|
+
"vue": {"source": "local", "paths": ["logs/app.log"]},
|
220
|
+
"nodejs": {"source": "local", "paths": ["logs/app.log", "npm-debug.log"]},
|
221
|
+
"django": {"source": "local", "paths": ["logs/django.log", "logs/debug.log"]},
|
222
|
+
"php": {"source": "local", "paths": ["storage/logs/laravel.log", "logs/error.log"]},
|
223
|
+
"rails": {"source": "local", "paths": ["log/development.log", "log/test.log"]},
|
224
|
+
"perl": {"source": "ssh", "host": "staging-server", "paths": ["/var/log/httpd/error_log"]},
|
225
|
+
"generic": {"source": "local", "paths": ["logs/app.log"]}
|
226
|
+
}
|
227
|
+
|
228
|
+
return log_configs.get(project_type, {"source": "local", "paths": ["logs/app.log"]})
|
229
|
+
|
230
|
+
|
231
|
+
def setup_update_checking(project_path: Path):
|
232
|
+
"""Set up automatic update checking configuration"""
|
233
|
+
|
234
|
+
cursorflow_dir = project_path / ".cursorflow"
|
235
|
+
cursorflow_dir.mkdir(exist_ok=True)
|
236
|
+
|
237
|
+
# Create update preferences
|
238
|
+
update_prefs = {
|
239
|
+
"check_interval_hours": 24,
|
240
|
+
"auto_update": False,
|
241
|
+
"include_prereleases": False,
|
242
|
+
"backup_before_update": True,
|
243
|
+
"last_check": None
|
244
|
+
}
|
245
|
+
|
246
|
+
prefs_file = cursorflow_dir / "update_preferences.json"
|
247
|
+
with open(prefs_file, 'w') as f:
|
248
|
+
json.dump(update_prefs, f, indent=2)
|
249
|
+
|
250
|
+
# Create initial version tracking
|
251
|
+
version_info = {
|
252
|
+
"installed_version": "1.0.0",
|
253
|
+
"rules_version": "1.0.0",
|
254
|
+
"installation_date": str(datetime.datetime.now().isoformat())
|
255
|
+
}
|
256
|
+
|
257
|
+
version_file = cursorflow_dir / "version_info.json"
|
258
|
+
with open(version_file, 'w') as f:
|
259
|
+
json.dump(version_info, f, indent=2)
|
260
|
+
|
261
|
+
print("✅ Update checking configured")
|
262
|
+
|
263
|
+
|
264
|
+
if __name__ == "__main__":
|
265
|
+
parser = argparse.ArgumentParser(description="Install CursorFlow rules in a project")
|
266
|
+
parser.add_argument("--project-dir", default=".", help="Project directory (default: current directory)")
|
267
|
+
|
268
|
+
args = parser.parse_args()
|
269
|
+
|
270
|
+
success = install_cursorflow_rules(args.project_dir)
|
271
|
+
exit(0 if success else 1)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: cursorflow
|
3
|
-
Version: 1.3.
|
3
|
+
Version: 1.3.2
|
4
4
|
Summary: Complete page intelligence for AI-driven development - captures DOM, network, console, and performance data
|
5
5
|
Author-email: GeekWarrior Development <support@cursorflow.dev>
|
6
6
|
License-Expression: MIT
|
@@ -77,8 +77,12 @@ All data structured for AI consumption:
|
|
77
77
|
# Install
|
78
78
|
pip install cursorflow
|
79
79
|
|
80
|
-
# Test any
|
81
|
-
cursorflow test
|
80
|
+
# Test any page - captures everything automatically
|
81
|
+
cursorflow test --base-url http://localhost:3000 --actions '[
|
82
|
+
{"navigate": "/dashboard"},
|
83
|
+
{"wait_for": "#main-content"},
|
84
|
+
{"screenshot": "dashboard-loaded"}
|
85
|
+
]'
|
82
86
|
|
83
87
|
# Compare mockup to implementation
|
84
88
|
cursorflow compare-mockup https://mockup.com/design --base-url http://localhost:3000
|
@@ -134,14 +138,31 @@ results = await flow.css_iteration_persistent(
|
|
134
138
|
## 🔧 CLI Commands
|
135
139
|
|
136
140
|
```bash
|
137
|
-
# Test
|
138
|
-
cursorflow test
|
141
|
+
# Test any page with custom actions
|
142
|
+
cursorflow test --base-url http://localhost:3000 --actions '[
|
143
|
+
{"navigate": "/login"},
|
144
|
+
{"fill": {"selector": "#username", "value": "test@example.com"}},
|
145
|
+
{"fill": {"selector": "#password", "value": "password123"}},
|
146
|
+
{"click": "#login-button"},
|
147
|
+
{"wait_for": ".dashboard"},
|
148
|
+
{"screenshot": "logged-in"}
|
149
|
+
]'
|
150
|
+
|
151
|
+
# Simple page test (just navigate and screenshot)
|
152
|
+
cursorflow test --base-url http://localhost:3000 --path "/dashboard"
|
139
153
|
|
140
154
|
# Compare mockup to implementation
|
141
|
-
cursorflow compare-mockup https://mockup.com/design
|
155
|
+
cursorflow compare-mockup https://mockup.com/design \
|
156
|
+
--base-url http://localhost:3000 \
|
157
|
+
--viewports '[{"width": 1440, "height": 900, "name": "desktop"}]'
|
142
158
|
|
143
159
|
# Iterate on CSS improvements
|
144
|
-
cursorflow iterate-mockup https://mockup.com/design
|
160
|
+
cursorflow iterate-mockup https://mockup.com/design \
|
161
|
+
--base-url http://localhost:3000 \
|
162
|
+
--css-improvements '[
|
163
|
+
{"name": "spacing", "css": ".container { gap: 2rem; }"},
|
164
|
+
{"name": "colors", "css": ".button { background: blue; }"}
|
165
|
+
]'
|
145
166
|
```
|
146
167
|
|
147
168
|
## 🌐 Universal Framework Support
|
@@ -1,6 +1,7 @@
|
|
1
1
|
cursorflow/__init__.py,sha256=nRmHnnnsbDH1A7_d3XkmzB5iJ44bt124zAQhaEhscyY,2450
|
2
2
|
cursorflow/auto_updater.py,sha256=oQ12TIMZ6Cm3HF-x9iRWFtvOLkRh-JWPqitS69-4roE,7851
|
3
|
-
cursorflow/cli.py,sha256=
|
3
|
+
cursorflow/cli.py,sha256=JRznfNAaXuthmCVwQX7yvX8FtAFrZYwemUA7BfvfFOo,25036
|
4
|
+
cursorflow/install_cursorflow_rules.py,sha256=Kc_rUs1oZ0-7oZE6LKEPCMnQUmixm5qgOe6rHzTCdoA,9041
|
4
5
|
cursorflow/updater.py,sha256=pvbSZgg6hgWZBE5AAUPppS5Yzv0yNMp2X_CL2GALg_w,18783
|
5
6
|
cursorflow/core/agent.py,sha256=f3lecgEzDRDdGTVccAtorpLGfNJJ49bbsQAmgr0vNGg,10136
|
6
7
|
cursorflow/core/auth_handler.py,sha256=oRafO6ZdxoHryBIvHsrNV8TECed4GXpJsdEiH0KdPPk,17149
|
@@ -19,9 +20,9 @@ cursorflow/core/persistent_session.py,sha256=FsEHj4wKkycmdp6PFRHv3g333Y74yqra0x_
|
|
19
20
|
cursorflow/core/report_generator.py,sha256=-vosfyrnfVyWDbAIMlMurl90xOXqBae8d6aLd9sEqiY,10113
|
20
21
|
cursorflow/log_sources/local_file.py,sha256=SwA294n_Ozg76ZUF5nPn5W2Fts_XtSOHEcO2S65vnjc,6768
|
21
22
|
cursorflow/log_sources/ssh_remote.py,sha256=TrE9FZ4aI6Cz1vChjvG8RC2KrNlgRKtG0_hC1w8pGDA,7106
|
22
|
-
cursorflow-1.3.
|
23
|
-
cursorflow-1.3.
|
24
|
-
cursorflow-1.3.
|
25
|
-
cursorflow-1.3.
|
26
|
-
cursorflow-1.3.
|
27
|
-
cursorflow-1.3.
|
23
|
+
cursorflow-1.3.2.dist-info/licenses/LICENSE,sha256=e4QbjAsj3bW-xgQOvQelr8sGLYDoqc48k6cKgCr_pBU,1080
|
24
|
+
cursorflow-1.3.2.dist-info/METADATA,sha256=jZu97_NLgtcgL5fHVbi7z7zE3_PVY7jqDfcwcXgQlMw,7659
|
25
|
+
cursorflow-1.3.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
26
|
+
cursorflow-1.3.2.dist-info/entry_points.txt,sha256=-Ed_n4Uff7wClEtWS-Py6xmQabecB9f0QAOjX0w7ljA,51
|
27
|
+
cursorflow-1.3.2.dist-info/top_level.txt,sha256=t1UZwRyZP4u-ng2CEcNHmk_ZT4ibQxoihB2IjTF7ovc,11
|
28
|
+
cursorflow-1.3.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|