cursorflow 2.2.2__py3-none-any.whl → 2.2.4__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/__init__.py CHANGED
@@ -56,7 +56,7 @@ def _get_version():
56
56
  pass
57
57
 
58
58
  # Fallback version - should match pyproject.toml
59
- return "2.2.2"
59
+ return "2.2.4"
60
60
 
61
61
  __version__ = _get_version()
62
62
  __author__ = "GeekWarrior Development"
cursorflow/cli.py CHANGED
@@ -90,6 +90,8 @@ def main(ctx):
90
90
  help='Timeout in seconds for wait operations')
91
91
  @click.option('--wait-for-network-idle', is_flag=True,
92
92
  help='Wait for network to be idle (no requests for 2s)')
93
+ @click.option('--wait', type=float,
94
+ help='Wait for specified seconds before continuing')
93
95
  @click.option('--click', multiple=True,
94
96
  help='Click element by selector (can specify multiple)')
95
97
  @click.option('--hover', multiple=True,
@@ -107,7 +109,7 @@ def main(ctx):
107
109
  @click.option('--quiet', '-q', is_flag=True,
108
110
  help='Minimal output, JSON results only')
109
111
  def test(base_url, path, actions, output, logs, config, verbose, headless, timeout, responsive,
110
- save_session, use_session, wait_for, wait_timeout, wait_for_network_idle,
112
+ save_session, use_session, wait_for, wait_timeout, wait_for_network_idle, wait,
111
113
  click, hover, fill, screenshot, open_trace, show_console, show_all_console, quiet):
112
114
  """
113
115
  Test UI flows and interactions with real-time log monitoring
@@ -149,6 +151,8 @@ def test(base_url, path, actions, output, logs, config, verbose, headless, timeo
149
151
  test_actions.append({"navigate": path})
150
152
 
151
153
  # Wait options
154
+ if wait:
155
+ test_actions.append({"wait_for_timeout": int(wait * 1000)})
152
156
  if wait_for:
153
157
  test_actions.append({"wait_for_selector": wait_for})
154
158
  if wait_for_network_idle:
@@ -909,6 +913,114 @@ def timeline(session):
909
913
  except Exception as e:
910
914
  console.print(f"[red]❌ Failed to load timeline: {e}[/red]")
911
915
 
916
+ @main.command()
917
+ @click.option('--artifacts', is_flag=True, help='Clean all artifacts (screenshots, traces)')
918
+ @click.option('--sessions', is_flag=True, help='Clean all saved sessions')
919
+ @click.option('--old-only', is_flag=True, help='Only clean artifacts older than 7 days')
920
+ @click.option('--all', 'clean_all', is_flag=True, help='Clean everything (artifacts, sessions, results)')
921
+ @click.option('--dry-run', is_flag=True, help='Show what would be deleted without deleting')
922
+ def cleanup(artifacts, sessions, old_only, clean_all, dry_run):
923
+ """
924
+ Clean up CursorFlow artifacts and data
925
+
926
+ Examples:
927
+ cursorflow cleanup --artifacts # Clean screenshots and traces
928
+ cursorflow cleanup --sessions # Clean saved sessions
929
+ cursorflow cleanup --all # Clean everything
930
+ cursorflow cleanup --old-only --artifacts # Clean old artifacts only
931
+ cursorflow cleanup --dry-run --all # Preview what would be deleted
932
+ """
933
+ import shutil
934
+ from datetime import datetime, timedelta
935
+
936
+ cursorflow_dir = Path('.cursorflow')
937
+
938
+ if not cursorflow_dir.exists():
939
+ console.print("[yellow]⚠️ No .cursorflow directory found[/yellow]")
940
+ return
941
+
942
+ total_size = 0
943
+ items_to_delete = []
944
+
945
+ # Calculate cutoff time for old-only mode
946
+ cutoff_time = datetime.now() - timedelta(days=7) if old_only else None
947
+
948
+ # Artifacts cleanup
949
+ if artifacts or clean_all:
950
+ artifacts_dir = cursorflow_dir / 'artifacts'
951
+ if artifacts_dir.exists():
952
+ for item in artifacts_dir.rglob('*'):
953
+ if item.is_file():
954
+ # Check age if old-only mode
955
+ if old_only:
956
+ file_time = datetime.fromtimestamp(item.stat().st_mtime)
957
+ if file_time > cutoff_time:
958
+ continue
959
+
960
+ size = item.stat().st_size
961
+ total_size += size
962
+ items_to_delete.append(('artifact', item, size))
963
+
964
+ # Sessions cleanup
965
+ if sessions or clean_all:
966
+ sessions_dir = cursorflow_dir / 'sessions'
967
+ if sessions_dir.exists():
968
+ for session_dir in sessions_dir.iterdir():
969
+ if session_dir.is_dir():
970
+ # Calculate session size
971
+ session_size = sum(f.stat().st_size for f in session_dir.rglob('*') if f.is_file())
972
+ total_size += session_size
973
+ items_to_delete.append(('session', session_dir, session_size))
974
+
975
+ # Display what will be deleted
976
+ if not items_to_delete:
977
+ console.print("✨ Nothing to clean - directory is already tidy!")
978
+ return
979
+
980
+ console.print(f"\n📊 Cleanup Summary:")
981
+ console.print(f" • Items to delete: {len(items_to_delete)}")
982
+ console.print(f" • Total size: {total_size / 1024 / 1024:.2f} MB")
983
+
984
+ # Show breakdown
985
+ artifact_count = sum(1 for t, _, _ in items_to_delete if t == 'artifact')
986
+ session_count = sum(1 for t, _, _ in items_to_delete if t == 'session')
987
+
988
+ if artifact_count:
989
+ artifact_size = sum(s for t, _, s in items_to_delete if t == 'artifact')
990
+ console.print(f" • Artifacts: {artifact_count} files ({artifact_size / 1024 / 1024:.2f} MB)")
991
+ if session_count:
992
+ session_size = sum(s for t, _, s in items_to_delete if t == 'session')
993
+ console.print(f" • Sessions: {session_count} sessions ({session_size / 1024 / 1024:.2f} MB)")
994
+
995
+ if dry_run:
996
+ console.print("\n🔍 Dry run - nothing deleted")
997
+ console.print(" Run without --dry-run to actually delete")
998
+ return
999
+
1000
+ # Confirm deletion
1001
+ import sys
1002
+ if sys.stdin.isatty():
1003
+ response = input("\n❓ Proceed with cleanup? [y/N]: ").strip().lower()
1004
+ if response != 'y':
1005
+ console.print("❌ Cleanup cancelled")
1006
+ return
1007
+
1008
+ # Delete items
1009
+ deleted_count = 0
1010
+ for item_type, item_path, _ in items_to_delete:
1011
+ try:
1012
+ if item_path.is_dir():
1013
+ shutil.rmtree(item_path)
1014
+ else:
1015
+ item_path.unlink()
1016
+ deleted_count += 1
1017
+ except Exception as e:
1018
+ console.print(f"[red]⚠️ Failed to delete {item_path}: {e}[/red]")
1019
+
1020
+ console.print(f"\n✅ Cleanup complete!")
1021
+ console.print(f" • Deleted {deleted_count}/{len(items_to_delete)} items")
1022
+ console.print(f" • Freed {total_size / 1024 / 1024:.2f} MB")
1023
+
912
1024
  @main.command()
913
1025
  @click.argument('project_path')
914
1026
  # Framework detection removed - CursorFlow is framework-agnostic
@@ -1313,7 +1313,7 @@ class BrowserController:
1313
1313
  const animInfo = {
1314
1314
  element_selector: element.tagName.toLowerCase() +
1315
1315
  (element.id ? '#' + element.id : '') +
1316
- (element.className ? '.' + element.className.split(' ').join('.') : ''),
1316
+ (element.className && typeof element.className === 'string' ? '.' + element.className.split(' ').join('.') : ''),
1317
1317
  animation_name: animation.animationName || 'transition',
1318
1318
  duration: animation.effect?.getTiming?.()?.duration || 0,
1319
1319
  delay: animation.effect?.getTiming?.()?.delay || 0,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cursorflow
3
- Version: 2.2.2
3
+ Version: 2.2.4
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
@@ -119,6 +119,31 @@ cursorflow test --actions '[
119
119
 
120
120
  ---
121
121
 
122
+ ## 🧹 Artifact Management
123
+
124
+ CursorFlow generates valuable debugging data (screenshots, traces, sessions). Manage disk space:
125
+
126
+ ```bash
127
+ # Clean old artifacts (>7 days)
128
+ cursorflow cleanup --artifacts --old-only
129
+
130
+ # Clean all artifacts
131
+ cursorflow cleanup --artifacts
132
+
133
+ # Clean saved sessions
134
+ cursorflow cleanup --sessions
135
+
136
+ # Clean everything
137
+ cursorflow cleanup --all
138
+
139
+ # Preview before deleting
140
+ cursorflow cleanup --all --dry-run
141
+ ```
142
+
143
+ **See:** [Artifact Cleanup Guide](docs/user/ARTIFACT_CLEANUP_GUIDE.md)
144
+
145
+ ---
146
+
122
147
  ## 🚀 Complete Page Intelligence
123
148
 
124
149
  Every test captures everything needed for debugging:
@@ -1,14 +1,14 @@
1
- cursorflow/__init__.py,sha256=UmNWQ3FzbteJbjMrv01dXJhSpgcA8UoReJsQO_fZAE8,2763
1
+ cursorflow/__init__.py,sha256=knSM_hFobem45sngePIIKfT4BRRDdFlHApyJuCyWJLU,2763
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=VYC_UJ0j3DggLUjNl82Q2dJNR_gWw-qWnIwRkSo3Oww,45151
4
+ cursorflow/cli.py,sha256=wVjgZP0zScwQxuXaXemnh_pKCAzO5MFerO4Q4Rn3Wm8,49898
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=jA3zmdULJb4FLn3pS3zlK5RmbpRK8k4UVgwiVM6_pts,146990
11
+ cursorflow/core/browser_controller.py,sha256=GLAdXP4JiMm27cNjpF_LyB8xV82Mo4_ZH56AC7hYpSs,147031
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
@@ -30,9 +30,9 @@ cursorflow/log_sources/ssh_remote.py,sha256=kZRpLpiO7cLd67wlCiTvz4Prwx1_Vu3ytB5K
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=hCbA9koCtRoeLOkB-PXmLlGzsag_15RuOveOE_R4JZ0,21628
33
- cursorflow-2.2.2.dist-info/licenses/LICENSE,sha256=e4QbjAsj3bW-xgQOvQelr8sGLYDoqc48k6cKgCr_pBU,1080
34
- cursorflow-2.2.2.dist-info/METADATA,sha256=1_uK1v9xGrwRg7xn2a9eSMIrNmloYFBDMIE1qdR-9Ws,14014
35
- cursorflow-2.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
36
- cursorflow-2.2.2.dist-info/entry_points.txt,sha256=-Ed_n4Uff7wClEtWS-Py6xmQabecB9f0QAOjX0w7ljA,51
37
- cursorflow-2.2.2.dist-info/top_level.txt,sha256=t1UZwRyZP4u-ng2CEcNHmk_ZT4ibQxoihB2IjTF7ovc,11
38
- cursorflow-2.2.2.dist-info/RECORD,,
33
+ cursorflow-2.2.4.dist-info/licenses/LICENSE,sha256=e4QbjAsj3bW-xgQOvQelr8sGLYDoqc48k6cKgCr_pBU,1080
34
+ cursorflow-2.2.4.dist-info/METADATA,sha256=bzgHTHdtixdH-KqgZBqVaaA2ZB_JAkI_tPmNikEL1jo,14520
35
+ cursorflow-2.2.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
36
+ cursorflow-2.2.4.dist-info/entry_points.txt,sha256=-Ed_n4Uff7wClEtWS-Py6xmQabecB9f0QAOjX0w7ljA,51
37
+ cursorflow-2.2.4.dist-info/top_level.txt,sha256=t1UZwRyZP4u-ng2CEcNHmk_ZT4ibQxoihB2IjTF7ovc,11
38
+ cursorflow-2.2.4.dist-info/RECORD,,