cursorflow 2.7.5__tar.gz → 2.7.7__tar.gz

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.
Files changed (55) hide show
  1. {cursorflow-2.7.5 → cursorflow-2.7.7}/PKG-INFO +40 -2
  2. {cursorflow-2.7.5 → cursorflow-2.7.7}/README.md +39 -1
  3. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/query_engine.py +85 -20
  4. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/rules/cursorflow-usage.mdc +133 -13
  5. {cursorflow-2.7.5 → cursorflow-2.7.7}/docs/user/USAGE_GUIDE.md +697 -17
  6. {cursorflow-2.7.5 → cursorflow-2.7.7}/pyproject.toml +1 -1
  7. {cursorflow-2.7.5 → cursorflow-2.7.7}/LICENSE +0 -0
  8. {cursorflow-2.7.5 → cursorflow-2.7.7}/MANIFEST.in +0 -0
  9. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/__init__.py +0 -0
  10. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/auto_init.py +0 -0
  11. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/auto_updater.py +0 -0
  12. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/cli.py +0 -0
  13. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/action_validator.py +0 -0
  14. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/agent.py +0 -0
  15. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/auth_handler.py +0 -0
  16. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/browser_controller.py +0 -0
  17. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/browser_engine.py +0 -0
  18. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/config_validator.py +0 -0
  19. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/css_iterator.py +0 -0
  20. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/cursor_integration.py +0 -0
  21. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/cursorflow.py +0 -0
  22. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/data_presenter.py +0 -0
  23. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/error_context_collector.py +0 -0
  24. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/error_correlator.py +0 -0
  25. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/event_correlator.py +0 -0
  26. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/file_change_monitor.py +0 -0
  27. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/hmr_detector.py +0 -0
  28. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/json_utils.py +0 -0
  29. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/log_collector.py +0 -0
  30. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/log_monitor.py +0 -0
  31. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/mockup_comparator.py +0 -0
  32. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/output_manager.py +0 -0
  33. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/persistent_session.py +0 -0
  34. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/report_generator.py +0 -0
  35. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/core/trace_manager.py +0 -0
  36. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/install_cursorflow_rules.py +0 -0
  37. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/log_sources/local_file.py +0 -0
  38. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/log_sources/ssh_remote.py +0 -0
  39. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/post_install.py +0 -0
  40. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/rules/__init__.py +0 -0
  41. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/rules/cursorflow-installation.mdc +0 -0
  42. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow/updater.py +0 -0
  43. {cursorflow-2.7.5 → cursorflow-2.7.7}/cursorflow.egg-info/SOURCES.txt +0 -0
  44. {cursorflow-2.7.5 → cursorflow-2.7.7}/examples/comprehensive_screenshot_example.py +0 -0
  45. {cursorflow-2.7.5 → cursorflow-2.7.7}/examples/element_inspection_example.py +0 -0
  46. {cursorflow-2.7.5 → cursorflow-2.7.7}/examples/element_measurement_example.py +0 -0
  47. {cursorflow-2.7.5 → cursorflow-2.7.7}/examples/enhanced_screenshot_example.py +0 -0
  48. {cursorflow-2.7.5 → cursorflow-2.7.7}/examples/hot_reload_css_iteration.py +0 -0
  49. {cursorflow-2.7.5 → cursorflow-2.7.7}/examples/mockup_comparison_example.py +0 -0
  50. {cursorflow-2.7.5 → cursorflow-2.7.7}/examples/opensas_example.py +0 -0
  51. {cursorflow-2.7.5 → cursorflow-2.7.7}/examples/react_example.py +0 -0
  52. {cursorflow-2.7.5 → cursorflow-2.7.7}/examples/responsive_testing_example.py +0 -0
  53. {cursorflow-2.7.5 → cursorflow-2.7.7}/examples/v2_comprehensive_demo.py +0 -0
  54. {cursorflow-2.7.5 → cursorflow-2.7.7}/setup.cfg +0 -0
  55. {cursorflow-2.7.5 → cursorflow-2.7.7}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cursorflow
3
- Version: 2.7.5
3
+ Version: 2.7.7
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
@@ -144,6 +144,44 @@ cursorflow cleanup --all --dry-run
144
144
 
145
145
  ---
146
146
 
147
+ ## 🔐 Authentication & Testing Protected Pages
148
+
149
+ Test authenticated pages with automatic session management:
150
+
151
+ ```bash
152
+ # 1. Configure auth in .cursorflow/config.json
153
+ {
154
+ "base_url": "http://localhost:3000",
155
+ "auth": {
156
+ "method": "form",
157
+ "username": "test@example.com",
158
+ "password": "testpass",
159
+ "username_selector": "#email",
160
+ "password_selector": "#password",
161
+ "submit_selector": "#login-button"
162
+ }
163
+ }
164
+
165
+ # 2. Login once and save session
166
+ cursorflow test --base-url http://localhost:3000 \
167
+ --path /login \
168
+ --save-session "user"
169
+
170
+ # 3. Reuse session for protected pages (no re-login!)
171
+ cursorflow test --use-session "user" \
172
+ --path /dashboard \
173
+ --screenshot "dashboard"
174
+ ```
175
+
176
+ **Supports:**
177
+ - Form authentication (username/password)
178
+ - Cookie authentication (JWT tokens, session cookies)
179
+ - Header authentication (Bearer tokens, API keys)
180
+
181
+ **See:** [Complete Authentication Guide](docs/user/USAGE_GUIDE.md#authentication--session-management)
182
+
183
+ ---
184
+
147
185
  ## 🚀 Complete Page Intelligence
148
186
 
149
187
  Every test captures everything needed for debugging:
@@ -157,7 +195,7 @@ Every test captures everything needed for debugging:
157
195
  - **Forms**: All field values at capture time (passwords masked)
158
196
  - **Performance**: Load times, memory usage, reliability indicators
159
197
  - **Visual**: Screenshots with comprehensive page analysis
160
- - **Sessions**: Save/restore authenticated browser state (requires auth_config)
198
+ - **Sessions**: Save/restore authenticated browser state (requires auth_config - see Authentication below)
161
199
 
162
200
  ### **🔄 Hot Reload Intelligence**
163
201
  - **Framework auto-detection** (Vite, Webpack, Next.js, Parcel, Laravel Mix)
@@ -99,6 +99,44 @@ cursorflow cleanup --all --dry-run
99
99
 
100
100
  ---
101
101
 
102
+ ## 🔐 Authentication & Testing Protected Pages
103
+
104
+ Test authenticated pages with automatic session management:
105
+
106
+ ```bash
107
+ # 1. Configure auth in .cursorflow/config.json
108
+ {
109
+ "base_url": "http://localhost:3000",
110
+ "auth": {
111
+ "method": "form",
112
+ "username": "test@example.com",
113
+ "password": "testpass",
114
+ "username_selector": "#email",
115
+ "password_selector": "#password",
116
+ "submit_selector": "#login-button"
117
+ }
118
+ }
119
+
120
+ # 2. Login once and save session
121
+ cursorflow test --base-url http://localhost:3000 \
122
+ --path /login \
123
+ --save-session "user"
124
+
125
+ # 3. Reuse session for protected pages (no re-login!)
126
+ cursorflow test --use-session "user" \
127
+ --path /dashboard \
128
+ --screenshot "dashboard"
129
+ ```
130
+
131
+ **Supports:**
132
+ - Form authentication (username/password)
133
+ - Cookie authentication (JWT tokens, session cookies)
134
+ - Header authentication (Bearer tokens, API keys)
135
+
136
+ **See:** [Complete Authentication Guide](docs/user/USAGE_GUIDE.md#authentication--session-management)
137
+
138
+ ---
139
+
102
140
  ## 🚀 Complete Page Intelligence
103
141
 
104
142
  Every test captures everything needed for debugging:
@@ -112,7 +150,7 @@ Every test captures everything needed for debugging:
112
150
  - **Forms**: All field values at capture time (passwords masked)
113
151
  - **Performance**: Load times, memory usage, reliability indicators
114
152
  - **Visual**: Screenshots with comprehensive page analysis
115
- - **Sessions**: Save/restore authenticated browser state (requires auth_config)
153
+ - **Sessions**: Save/restore authenticated browser state (requires auth_config - see Authentication below)
116
154
 
117
155
  ### **🔄 Hot Reload Intelligence**
118
156
  - **Framework auto-detection** (Vite, Webpack, Next.js, Parcel, Laravel Mix)
@@ -420,29 +420,90 @@ class QueryEngine:
420
420
 
421
421
  # Phase 1: Enhanced DOM filtering
422
422
 
423
- # Filter by selector (improved matching)
423
+ # Filter by selector (improved matching with correct field paths and priority)
424
424
  if 'selector' in filters or 'select' in filters:
425
425
  selector = filters.get('selector') or filters.get('select')
426
- # Remove leading dot if present (e.g., ".class" -> "class")
427
- selector_clean = selector.lstrip('.')
428
426
 
429
- filtered_elements = [
430
- el for el in filtered_elements
427
+ # Detect selector type
428
+ is_id_selector = selector.startswith('#')
429
+ is_class_selector = selector.startswith('.')
430
+
431
+ # Remove leading dot or hash if present (e.g., ".class" -> "class", "#id" -> "id")
432
+ selector_clean = selector.lstrip('.#')
433
+
434
+ # Determine if this looks like a simple tag name (no special characters)
435
+ is_simple_tag = selector.isalpha() and not is_id_selector and not is_class_selector
436
+
437
+ result_elements = []
438
+ for el in filtered_elements:
439
+ matched = False
440
+
441
+ # Priority 1: ID selector (#id) - only check ID field
442
+ if is_id_selector:
443
+ if selector_clean == el.get('id', ''):
444
+ result_elements.append(el)
445
+ continue
446
+
447
+ # Priority 2: Class selector (.class) - only check className
448
+ if is_class_selector:
449
+ if el.get('className'):
450
+ class_names = str(el.get('className')).split()
451
+ if selector_clean in class_names:
452
+ result_elements.append(el)
453
+ # Backward compatibility: Check classes array (old format)
454
+ elif selector_clean in el.get('classes', []):
455
+ result_elements.append(el)
456
+ continue
457
+
458
+ # Priority 3: For simple alphanumeric selectors, check tagName, ID, and className
459
+ # This handles ambiguous cases like "page" (could be tag or ID)
460
+ if is_simple_tag:
461
+ # Check tag name match (exact, case insensitive)
462
+ if selector.lower() == el.get('tagName', '').lower():
463
+ result_elements.append(el)
464
+ continue
465
+
466
+ # Check ID match (exact)
467
+ if selector_clean == el.get('id', ''):
468
+ result_elements.append(el)
469
+ continue
470
+
471
+ # Class name match (whole word match to avoid "a" matching "navbar")
472
+ if el.get('className'):
473
+ class_names = str(el.get('className')).split()
474
+ if selector_clean in class_names:
475
+ result_elements.append(el)
476
+ continue
477
+
478
+ # Backward compatibility: Check classes array (old format)
479
+ if selector_clean in el.get('classes', []):
480
+ result_elements.append(el)
481
+
482
+ # Don't fall through to selector string checks for simple tags
483
+ continue
484
+
485
+ # Priority 2: For complex selectors, check selector strings and attributes
431
486
  if (
432
- # Check nested uniqueSelector
487
+ # Check selectors.unique_css (current format)
488
+ (selector in el.get('selectors', {}).get('unique_css', '')) or
489
+ # Check selectors.css (current format)
490
+ (selector in el.get('selectors', {}).get('css', '')) or
491
+ # Check selectors.xpath
492
+ (selector in el.get('selectors', {}).get('xpath', '')) or
493
+ # Check ID (exact match or contains for partial IDs)
494
+ (el.get('id') and selector_clean in str(el.get('id'))) or
495
+ # Check className (can be string or None)
496
+ (el.get('className') and selector_clean in str(el.get('className'))) or
497
+ # Backward compatibility: Check nested uniqueSelector (old format)
433
498
  (selector in el.get('selectors', {}).get('uniqueSelector', '')) or
434
- # Check top-level uniqueSelector (old format)
499
+ # Backward compatibility: Check top-level uniqueSelector (old format)
435
500
  (selector in el.get('uniqueSelector', '')) or
436
- # Check tagName
437
- (selector in el.get('tagName', '')) or
438
- # Check ID
439
- (selector == el.get('id', '')) or
440
- # Check className string
441
- (el.get('className') and selector_clean in el.get('className', '')) or
442
- # Check classes array (old format)
501
+ # Backward compatibility: Check classes array (old format)
443
502
  (selector_clean in el.get('classes', []))
444
- )
445
- ]
503
+ ):
504
+ result_elements.append(el)
505
+
506
+ filtered_elements = result_elements
446
507
 
447
508
  # Filter by attributes
448
509
  if 'with_attr' in filters:
@@ -460,18 +521,18 @@ class QueryEngine:
460
521
  if el.get('accessibility', {}).get('role') == role
461
522
  ]
462
523
 
463
- # Filter by visibility
524
+ # Filter by visibility (use correct nested path)
464
525
  if 'visible' in filters and filters['visible']:
465
526
  filtered_elements = [
466
527
  el for el in filtered_elements
467
- if el.get('visual_context', {}).get('isVisible', True)
528
+ if el.get('visual_context', {}).get('visibility', {}).get('is_visible', False)
468
529
  ]
469
530
 
470
- # Filter by interactivity
531
+ # Filter by interactivity (use correct nested path)
471
532
  if 'interactive' in filters and filters['interactive']:
472
533
  filtered_elements = [
473
534
  el for el in filtered_elements
474
- if el.get('accessibility', {}).get('isInteractive', False)
535
+ if el.get('accessibility', {}).get('is_interactive', False)
475
536
  ]
476
537
 
477
538
  # Filter elements with errors (from console errors)
@@ -958,6 +1019,10 @@ class QueryEngine:
958
1019
  elif format == "csv":
959
1020
  return self._to_csv(data, data_type)
960
1021
 
1022
+ elif format == "dict" or format == "raw":
1023
+ # Return raw dictionary (useful for programmatic access)
1024
+ return data
1025
+
961
1026
  else:
962
1027
  return data
963
1028
 
@@ -963,21 +963,141 @@ cursorflow test --base-url http://localhost:3000 --actions '[{"navigate": "/dash
963
963
  cursorflow test --base-url http://localhost:3000 --actions '[{"navigate": "/dashboard"}, {"screenshot": "after"}]'
964
964
  ```
965
965
 
966
- ## Authentication Testing
966
+ ## Authentication & Session Management
967
967
 
968
+ ### **Critical: Most Real Apps Need Auth**
969
+
970
+ Testing sophisticated applications requires authentication to access:
971
+ - User dashboards and protected pages
972
+ - Admin panels and settings
973
+ - Role-based features
974
+ - Shopping carts and user data
975
+ - Personalized content
976
+
977
+ ### **Three Authentication Methods**
978
+
979
+ #### **Method 1: Form Authentication (Automatic)**
980
+
981
+ Configure in `.cursorflow/config.json`:
982
+ ```json
983
+ {
984
+ "base_url": "http://localhost:3000",
985
+ "auth": {
986
+ "method": "form",
987
+ "username": "test@example.com",
988
+ "password": "testpass",
989
+ "username_selector": "#email",
990
+ "password_selector": "#password",
991
+ "submit_selector": "#login-button",
992
+ "success_indicators": ["dashboard", "profile"],
993
+ "auth_check_selectors": [".user-menu"]
994
+ }
995
+ }
996
+ ```
997
+
998
+ Then use session management:
968
999
  ```bash
969
- cursorflow test \
970
- --base-url http://localhost:3000 \
971
- --actions '[
972
- {"navigate": "/login"},
973
- {"fill": {"selector": "#username", "value": "test@example.com"}},
974
- {"fill": {"selector": "#password", "value": "testpass"}},
975
- {"click": "#login-button"},
976
- {"wait_for": ".dashboard"},
977
- {"navigate": "/protected-page"},
978
- {"wait_for": "#protected-content"},
979
- {"screenshot": "authenticated"}
980
- ]'
1000
+ # Login once, save session
1001
+ cursorflow test --base-url http://localhost:3000 \
1002
+ --path /login \
1003
+ --save-session "user"
1004
+
1005
+ # Reuse session (no re-login!)
1006
+ cursorflow test --use-session "user" \
1007
+ --path /dashboard \
1008
+ --screenshot "dashboard"
1009
+ ```
1010
+
1011
+ #### **Method 2: Cookie Authentication**
1012
+
1013
+ For JWT tokens, session cookies, or cookies from DevTools:
1014
+ ```json
1015
+ {
1016
+ "auth": {
1017
+ "method": "cookies",
1018
+ "cookies": [
1019
+ {
1020
+ "name": "session_token",
1021
+ "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
1022
+ "domain": "example.com",
1023
+ "path": "/",
1024
+ "httpOnly": true,
1025
+ "secure": true
1026
+ }
1027
+ ]
1028
+ }
1029
+ }
1030
+ ```
1031
+
1032
+ #### **Method 3: Header Authentication**
1033
+
1034
+ For API tokens and Bearer authentication:
1035
+ ```json
1036
+ {
1037
+ "auth": {
1038
+ "method": "headers",
1039
+ "headers": {
1040
+ "Authorization": "Bearer your-api-token",
1041
+ "X-API-Key": "your-api-key"
1042
+ }
1043
+ }
1044
+ }
1045
+ ```
1046
+
1047
+ ### **Session Management Benefits**
1048
+
1049
+ **Without sessions**: Re-login on every test (slow, server load)
1050
+ **With sessions**: Login once, reuse state (fast, efficient)
1051
+
1052
+ ```bash
1053
+ # Save sessions for different roles
1054
+ cursorflow test --path /login --save-session "admin"
1055
+ cursorflow test --path /login --save-session "user"
1056
+
1057
+ # Reuse as needed
1058
+ cursorflow test --use-session "admin" --path /admin/settings
1059
+ cursorflow test --use-session "user" --path /dashboard
1060
+ ```
1061
+
1062
+ ### **Manual Authentication (Complex Flows)**
1063
+
1064
+ For 2FA, OAuth, or complex flows, use explicit actions:
1065
+ ```bash
1066
+ cursorflow test --actions '[
1067
+ {"navigate": "/login"},
1068
+ {"fill": {"selector": "#email", "value": "test@example.com"}},
1069
+ {"fill": {"selector": "#password", "value": "testpass"}},
1070
+ {"click": "#login-button"},
1071
+ {"wait_for": "#otp-input"},
1072
+ {"fill": {"selector": "#otp-input", "value": "123456"}},
1073
+ {"click": "#verify-button"},
1074
+ {"wait_for": ".dashboard"},
1075
+ {"screenshot": "authenticated"}
1076
+ ]' --save-session "2fa-user"
1077
+ ```
1078
+
1079
+ ### **Troubleshooting Auth**
1080
+
1081
+ **Auth failing?**
1082
+ ```bash
1083
+ # Inspect login form to get correct selectors
1084
+ cursorflow inspect --base-url http://localhost:3000 \
1085
+ --path /login \
1086
+ --selector "input[type='email']"
1087
+
1088
+ # Test with verbose logging
1089
+ cursorflow test --path /login \
1090
+ --save-session "test" \
1091
+ --verbose
1092
+ ```
1093
+
1094
+ **Session not working?**
1095
+ ```bash
1096
+ # Check saved session
1097
+ cat .cursorflow/sessions/user_session.json
1098
+
1099
+ # Force fresh login
1100
+ cursorflow test --use-session "user" --fresh-session
981
1101
  ```
982
1102
 
983
1103
  ## Best Practices