cursorflow 2.7.7__tar.gz → 2.7.9__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.
- {cursorflow-2.7.7 → cursorflow-2.7.9}/PKG-INFO +17 -1
- {cursorflow-2.7.7 → cursorflow-2.7.9}/README.md +16 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/cli.py +197 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/rules/cursorflow-usage.mdc +53 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/docs/user/USAGE_GUIDE.md +211 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/pyproject.toml +1 -1
- {cursorflow-2.7.7 → cursorflow-2.7.9}/LICENSE +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/MANIFEST.in +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/__init__.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/auto_init.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/auto_updater.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/action_validator.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/agent.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/auth_handler.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/browser_controller.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/browser_engine.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/config_validator.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/css_iterator.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/cursor_integration.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/cursorflow.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/data_presenter.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/error_context_collector.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/error_correlator.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/event_correlator.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/file_change_monitor.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/hmr_detector.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/json_utils.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/log_collector.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/log_monitor.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/mockup_comparator.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/output_manager.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/persistent_session.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/query_engine.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/report_generator.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/core/trace_manager.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/install_cursorflow_rules.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/log_sources/local_file.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/log_sources/ssh_remote.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/post_install.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/rules/__init__.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/rules/cursorflow-installation.mdc +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow/updater.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/cursorflow.egg-info/SOURCES.txt +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/examples/comprehensive_screenshot_example.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/examples/element_inspection_example.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/examples/element_measurement_example.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/examples/enhanced_screenshot_example.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/examples/hot_reload_css_iteration.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/examples/mockup_comparison_example.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/examples/opensas_example.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/examples/react_example.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/examples/responsive_testing_example.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/examples/v2_comprehensive_demo.py +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/setup.cfg +0 -0
- {cursorflow-2.7.7 → cursorflow-2.7.9}/setup.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: cursorflow
|
3
|
-
Version: 2.7.
|
3
|
+
Version: 2.7.9
|
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
|
@@ -177,6 +177,22 @@ cursorflow test --use-session "user" \
|
|
177
177
|
- Form authentication (username/password)
|
178
178
|
- Cookie authentication (JWT tokens, session cookies)
|
179
179
|
- Header authentication (Bearer tokens, API keys)
|
180
|
+
- SSO authentication (Google, Microsoft, Okta, Auth0)
|
181
|
+
|
182
|
+
**SSO/OAuth Quick Start:**
|
183
|
+
```bash
|
184
|
+
# Capture SSO auth (opens browser for manual login)
|
185
|
+
cursorflow capture-auth --base-url http://localhost:3000 \
|
186
|
+
--path /dashboard \
|
187
|
+
--browser chrome \
|
188
|
+
--output google-sso.json
|
189
|
+
|
190
|
+
# Use captured auth
|
191
|
+
# (Copy cookies from google-sso.json to .cursorflow/config.json)
|
192
|
+
cursorflow test --use-session "sso-user" --path /dashboard
|
193
|
+
```
|
194
|
+
|
195
|
+
**Tip:** Use `--browser chrome` on macOS for better window visibility
|
180
196
|
|
181
197
|
**See:** [Complete Authentication Guide](docs/user/USAGE_GUIDE.md#authentication--session-management)
|
182
198
|
|
@@ -132,6 +132,22 @@ cursorflow test --use-session "user" \
|
|
132
132
|
- Form authentication (username/password)
|
133
133
|
- Cookie authentication (JWT tokens, session cookies)
|
134
134
|
- Header authentication (Bearer tokens, API keys)
|
135
|
+
- SSO authentication (Google, Microsoft, Okta, Auth0)
|
136
|
+
|
137
|
+
**SSO/OAuth Quick Start:**
|
138
|
+
```bash
|
139
|
+
# Capture SSO auth (opens browser for manual login)
|
140
|
+
cursorflow capture-auth --base-url http://localhost:3000 \
|
141
|
+
--path /dashboard \
|
142
|
+
--browser chrome \
|
143
|
+
--output google-sso.json
|
144
|
+
|
145
|
+
# Use captured auth
|
146
|
+
# (Copy cookies from google-sso.json to .cursorflow/config.json)
|
147
|
+
cursorflow test --use-session "sso-user" --path /dashboard
|
148
|
+
```
|
149
|
+
|
150
|
+
**Tip:** Use `--browser chrome` on macOS for better window visibility
|
135
151
|
|
136
152
|
**See:** [Complete Authentication Guide](docs/user/USAGE_GUIDE.md#authentication--session-management)
|
137
153
|
|
@@ -1116,6 +1116,203 @@ def sessions(subcommand, name):
|
|
1116
1116
|
else:
|
1117
1117
|
console.print(f"[yellow]⚠️ Session not found: {name}[/yellow]")
|
1118
1118
|
|
1119
|
+
@main.command()
|
1120
|
+
@click.option('--base-url', '-u', required=True, help='Base URL of your application')
|
1121
|
+
@click.option('--path', '-p', default='/', help='Path to navigate to after login (e.g., /dashboard)')
|
1122
|
+
@click.option('--output', '-o', default='auth-capture.json', help='Output file for captured auth state')
|
1123
|
+
@click.option('--wait', type=int, default=60, help='Seconds to wait for manual login (default: 60)')
|
1124
|
+
@click.option('--browser', type=click.Choice(['chromium', 'chrome', 'firefox']), default='chromium', help='Browser to use (default: chromium)')
|
1125
|
+
def capture_auth(base_url, path, output, wait, browser):
|
1126
|
+
"""
|
1127
|
+
Capture authentication state after manual SSO/OAuth login
|
1128
|
+
|
1129
|
+
Opens a browser, waits for you to complete SSO login manually,
|
1130
|
+
then captures all cookies, localStorage, and sessionStorage.
|
1131
|
+
Perfect for Google/Microsoft/Okta SSO authentication.
|
1132
|
+
|
1133
|
+
\b
|
1134
|
+
Process:
|
1135
|
+
1. Browser opens to your app
|
1136
|
+
2. Complete SSO login manually (Google, Microsoft, Okta, etc.)
|
1137
|
+
3. Navigate to a protected page (e.g., /dashboard)
|
1138
|
+
4. CursorFlow captures all auth state
|
1139
|
+
5. Auth state saved to JSON file
|
1140
|
+
6. Use in .cursorflow/config.json as cookie authentication
|
1141
|
+
|
1142
|
+
\b
|
1143
|
+
Examples:
|
1144
|
+
# Capture Google SSO auth
|
1145
|
+
cursorflow capture-auth --base-url http://localhost:3000 --path /dashboard
|
1146
|
+
|
1147
|
+
# Use system Chrome (more visible on macOS)
|
1148
|
+
cursorflow capture-auth -u http://localhost:3000 --browser chrome
|
1149
|
+
|
1150
|
+
# Capture with custom wait time
|
1151
|
+
cursorflow capture-auth -u http://localhost:3000 -p /dashboard --wait 120
|
1152
|
+
|
1153
|
+
# Save to custom file
|
1154
|
+
cursorflow capture-auth -u http://localhost:3000 --output google-sso.json
|
1155
|
+
"""
|
1156
|
+
console.print(f"\n🔐 [bold]SSO Authentication Capture[/bold]")
|
1157
|
+
console.print(f"📍 Base URL: [cyan]{base_url}[/cyan]")
|
1158
|
+
console.print(f"🎯 Target path: [cyan]{path}[/cyan]")
|
1159
|
+
console.print(f"⏱️ Wait time: [yellow]{wait}[/yellow] seconds")
|
1160
|
+
console.print(f"📄 Output file: [green]{output}[/green]\n")
|
1161
|
+
|
1162
|
+
console.print("📋 [bold yellow]Instructions:[/bold yellow]")
|
1163
|
+
console.print(" 1. [bold]A Chromium browser window will open[/bold]")
|
1164
|
+
console.print(" 2. [yellow]Complete SSO login manually[/yellow] in that browser window")
|
1165
|
+
console.print(" 3. Navigate to a protected page (e.g., /dashboard)")
|
1166
|
+
console.print(" 4. Return here and [green]press Enter[/green] when fully logged in")
|
1167
|
+
console.print(" 5. CursorFlow will capture all auth state\n")
|
1168
|
+
|
1169
|
+
console.print("[bold red]⚠️ Look for the browser window - it may open behind other windows![/bold red]\n")
|
1170
|
+
|
1171
|
+
input("Press Enter to open browser and start capture...")
|
1172
|
+
|
1173
|
+
try:
|
1174
|
+
from playwright.async_api import async_playwright
|
1175
|
+
import json
|
1176
|
+
|
1177
|
+
async def capture_process():
|
1178
|
+
console.print("\n🚀 Starting Playwright...")
|
1179
|
+
async with async_playwright() as p:
|
1180
|
+
# Select browser based on user choice
|
1181
|
+
if browser == 'chrome':
|
1182
|
+
browser_type = p.chromium
|
1183
|
+
channel = 'chrome' # Use system Chrome if available
|
1184
|
+
elif browser == 'firefox':
|
1185
|
+
browser_type = p.firefox
|
1186
|
+
channel = None
|
1187
|
+
else: # chromium
|
1188
|
+
browser_type = p.chromium
|
1189
|
+
channel = None
|
1190
|
+
|
1191
|
+
# Launch browser in HEADED mode (user needs to interact)
|
1192
|
+
console.print(f"🌐 Launching [bold]{browser}[/bold] browser (headed mode)...")
|
1193
|
+
console.print("[yellow]👀 Watch for browser window - it should appear shortly...[/yellow]")
|
1194
|
+
|
1195
|
+
try:
|
1196
|
+
launch_options = {
|
1197
|
+
'headless': False,
|
1198
|
+
'slow_mo': 50,
|
1199
|
+
'args': ['--start-maximized']
|
1200
|
+
}
|
1201
|
+
if channel:
|
1202
|
+
launch_options['channel'] = channel
|
1203
|
+
|
1204
|
+
browser_instance = await browser_type.launch(**launch_options)
|
1205
|
+
except Exception as e:
|
1206
|
+
console.print(f"[red]❌ Failed to launch browser: {e}[/red]")
|
1207
|
+
console.print("\n💡 Try installing Chromium:")
|
1208
|
+
console.print(" [cyan]playwright install chromium[/cyan]")
|
1209
|
+
raise
|
1210
|
+
|
1211
|
+
# Create context with viewport to ensure it's visible
|
1212
|
+
context = await browser_instance.new_context(
|
1213
|
+
viewport={'width': 1280, 'height': 720}
|
1214
|
+
)
|
1215
|
+
page = await context.new_page()
|
1216
|
+
|
1217
|
+
# Bring page to front
|
1218
|
+
await page.bring_to_front()
|
1219
|
+
|
1220
|
+
console.print(f"\n✅ [bold green]Browser window opened![/bold green]")
|
1221
|
+
console.print(f" 👉 [bold]If you don't see it, check behind other windows or different desktop spaces[/bold]")
|
1222
|
+
console.print(f"\n🌐 Navigating to: [cyan]{base_url}[/cyan]...")
|
1223
|
+
await page.goto(base_url)
|
1224
|
+
console.print(f"✅ Page loaded!")
|
1225
|
+
|
1226
|
+
console.print(f"\n⏳ [yellow]Complete your SSO login in the browser...[/yellow]")
|
1227
|
+
console.print(f" Waiting up to {wait} seconds...")
|
1228
|
+
console.print(f" [bold]Press Enter in this terminal when logged in and on {path}[/bold]\n")
|
1229
|
+
|
1230
|
+
# Wait for user to complete login
|
1231
|
+
import sys
|
1232
|
+
import select
|
1233
|
+
|
1234
|
+
# Simple blocking wait for Enter key
|
1235
|
+
input("Press Enter after completing login... ")
|
1236
|
+
|
1237
|
+
# Navigate to target path to ensure we're at the right place
|
1238
|
+
if path != '/':
|
1239
|
+
console.print(f"📍 Navigating to: [cyan]{path}[/cyan]")
|
1240
|
+
await page.goto(f"{base_url.rstrip('/')}{path}")
|
1241
|
+
await page.wait_for_load_state("networkidle")
|
1242
|
+
|
1243
|
+
console.print("\n📸 Capturing authentication state...")
|
1244
|
+
|
1245
|
+
# Capture all authentication data
|
1246
|
+
storage_state = await context.storage_state()
|
1247
|
+
|
1248
|
+
# Get localStorage
|
1249
|
+
local_storage = await page.evaluate("""
|
1250
|
+
() => {
|
1251
|
+
const storage = {};
|
1252
|
+
for (let i = 0; i < localStorage.length; i++) {
|
1253
|
+
const key = localStorage.key(i);
|
1254
|
+
storage[key] = localStorage.getItem(key);
|
1255
|
+
}
|
1256
|
+
return storage;
|
1257
|
+
}
|
1258
|
+
""")
|
1259
|
+
|
1260
|
+
# Get sessionStorage
|
1261
|
+
session_storage = await page.evaluate("""
|
1262
|
+
() => {
|
1263
|
+
const storage = {};
|
1264
|
+
for (let i = 0; i < sessionStorage.length; i++) {
|
1265
|
+
const key = sessionStorage.key(i);
|
1266
|
+
storage[key] = sessionStorage.getItem(key);
|
1267
|
+
}
|
1268
|
+
return storage;
|
1269
|
+
}
|
1270
|
+
""")
|
1271
|
+
|
1272
|
+
# Organize captured data
|
1273
|
+
auth_data = {
|
1274
|
+
"captured_at": time.strftime("%Y-%m-%d %H:%M:%S"),
|
1275
|
+
"base_url": base_url,
|
1276
|
+
"current_url": page.url,
|
1277
|
+
"method": "cookies",
|
1278
|
+
"cookies": storage_state.get("cookies", []),
|
1279
|
+
"localStorage": local_storage,
|
1280
|
+
"sessionStorage": session_storage,
|
1281
|
+
"usage_instructions": {
|
1282
|
+
"1": "Copy the 'cookies' array below",
|
1283
|
+
"2": "Add to .cursorflow/config.json under auth.cookies",
|
1284
|
+
"3": "Set auth.method to 'cookies'",
|
1285
|
+
"4": "Use with: cursorflow test --use-session <name>"
|
1286
|
+
}
|
1287
|
+
}
|
1288
|
+
|
1289
|
+
# Save to file
|
1290
|
+
output_path = Path(output)
|
1291
|
+
with open(output_path, 'w') as f:
|
1292
|
+
json.dump(auth_data, f, indent=2)
|
1293
|
+
|
1294
|
+
console.print(f"\n✅ Authentication state captured!")
|
1295
|
+
console.print(f"📄 Saved to: [green]{output_path.absolute()}[/green]")
|
1296
|
+
console.print(f"🍪 Captured {len(auth_data['cookies'])} cookies")
|
1297
|
+
console.print(f"💾 localStorage: {len(local_storage)} items")
|
1298
|
+
console.print(f"💾 sessionStorage: {len(session_storage)} items")
|
1299
|
+
|
1300
|
+
console.print(f"\n📋 [bold]Next steps:[/bold]")
|
1301
|
+
console.print(f" 1. Open: [cyan]{output}[/cyan]")
|
1302
|
+
console.print(f" 2. Copy the 'cookies' array")
|
1303
|
+
console.print(f" 3. Add to .cursorflow/config.json:")
|
1304
|
+
console.print(f'\n {{\n "auth": {{\n "method": "cookies",\n "cookies": [... paste here ...]\n }}\n }}\n')
|
1305
|
+
console.print(f" 4. Test with: [cyan]cursorflow test --use-session sso-user[/cyan]\n")
|
1306
|
+
|
1307
|
+
await browser_instance.close()
|
1308
|
+
|
1309
|
+
asyncio.run(capture_process())
|
1310
|
+
|
1311
|
+
except KeyboardInterrupt:
|
1312
|
+
console.print("\n[yellow]⚠️ Capture cancelled by user[/yellow]")
|
1313
|
+
except Exception as e:
|
1314
|
+
console.print(f"[red]❌ Error capturing auth: {escape(str(e))}[/red]")
|
1315
|
+
|
1119
1316
|
@main.command()
|
1120
1317
|
@click.option('--base-url', '-u', required=True)
|
1121
1318
|
@click.option('--path', '-p', default='/', help='Path to navigate to')
|
@@ -1076,6 +1076,47 @@ cursorflow test --actions '[
|
|
1076
1076
|
]' --save-session "2fa-user"
|
1077
1077
|
```
|
1078
1078
|
|
1079
|
+
### **SSO Authentication (Google, Microsoft, Okta)**
|
1080
|
+
|
1081
|
+
**SSO requires manual capture** because of external identity providers:
|
1082
|
+
|
1083
|
+
```bash
|
1084
|
+
# 1. Capture SSO auth (opens browser, you login manually)
|
1085
|
+
cursorflow capture-auth --base-url http://localhost:3000 \
|
1086
|
+
--path /dashboard \
|
1087
|
+
--browser chrome \
|
1088
|
+
--output google-sso.json
|
1089
|
+
|
1090
|
+
# Browser opens (use --browser chrome for better visibility on macOS)
|
1091
|
+
# You complete SSO login, CursorFlow captures cookies
|
1092
|
+
|
1093
|
+
# 2. Copy cookies from google-sso.json to .cursorflow/config.json:
|
1094
|
+
{
|
1095
|
+
"auth": {
|
1096
|
+
"method": "cookies",
|
1097
|
+
"cookies": [/* paste from google-sso.json */]
|
1098
|
+
}
|
1099
|
+
}
|
1100
|
+
|
1101
|
+
# 3. Use captured auth
|
1102
|
+
cursorflow test --use-session "sso-user" --path /dashboard
|
1103
|
+
```
|
1104
|
+
|
1105
|
+
**SSO providers supported:**
|
1106
|
+
- Google OAuth
|
1107
|
+
- Microsoft Azure AD
|
1108
|
+
- Okta
|
1109
|
+
- Auth0
|
1110
|
+
- Any OAuth/SAML provider
|
1111
|
+
|
1112
|
+
**When SSO tokens expire:**
|
1113
|
+
```bash
|
1114
|
+
# Re-capture auth (SSO tokens typically expire in 1-24 hours)
|
1115
|
+
cursorflow capture-auth --base-url http://localhost:3000 \
|
1116
|
+
--path /dashboard \
|
1117
|
+
--output sso-refreshed.json
|
1118
|
+
```
|
1119
|
+
|
1079
1120
|
### **Troubleshooting Auth**
|
1080
1121
|
|
1081
1122
|
**Auth failing?**
|
@@ -1100,6 +1141,18 @@ cat .cursorflow/sessions/user_session.json
|
|
1100
1141
|
cursorflow test --use-session "user" --fresh-session
|
1101
1142
|
```
|
1102
1143
|
|
1144
|
+
**SSO not working?**
|
1145
|
+
```bash
|
1146
|
+
# Re-capture auth state
|
1147
|
+
cursorflow capture-auth --base-url http://localhost:3000 --path /dashboard
|
1148
|
+
|
1149
|
+
# Check if localStorage has tokens (some SSO stores tokens there)
|
1150
|
+
cat auth-capture.json | grep localStorage
|
1151
|
+
|
1152
|
+
# Test immediately after capture
|
1153
|
+
cursorflow test --use-session "sso-user" --path /dashboard
|
1154
|
+
```
|
1155
|
+
|
1103
1156
|
## Best Practices
|
1104
1157
|
|
1105
1158
|
### **🔥 Hot Reload CSS Iteration Best Practices**
|
@@ -1056,6 +1056,31 @@ Clicked submit: button[type='submit']
|
|
1056
1056
|
cat .cursorflow/sessions/test_session.json | python3 -m json.tool
|
1057
1057
|
```
|
1058
1058
|
|
1059
|
+
**Problem: "Browser not appearing" (capture-auth)**
|
1060
|
+
|
1061
|
+
**Solution:**
|
1062
|
+
|
1063
|
+
The browser IS launching but may be hidden by macOS window management:
|
1064
|
+
|
1065
|
+
1. **Use system Chrome** (more visible):
|
1066
|
+
```bash
|
1067
|
+
cursorflow capture-auth --base-url http://localhost:3000 \
|
1068
|
+
--browser chrome \
|
1069
|
+
--path /dashboard
|
1070
|
+
```
|
1071
|
+
|
1072
|
+
2. **Check all desktop spaces**:
|
1073
|
+
- Press F3 or swipe up with 3 fingers (Mission Control)
|
1074
|
+
- Look for Chromium/Chrome window
|
1075
|
+
|
1076
|
+
3. **Check your Dock**:
|
1077
|
+
- Look for Chromium icon that appeared
|
1078
|
+
- Click to bring window forward
|
1079
|
+
|
1080
|
+
4. **Verify browser launched**:
|
1081
|
+
- Look for "✅ Browser opened!" in terminal output
|
1082
|
+
- If you see this, browser is running somewhere
|
1083
|
+
|
1059
1084
|
---
|
1060
1085
|
|
1061
1086
|
#### **Advanced Authentication Scenarios**
|
@@ -1134,6 +1159,192 @@ cursorflow test --use-session "regular-user" \
|
|
1134
1159
|
3. Look at Response Headers for `Set-Cookie`
|
1135
1160
|
4. Copy cookie details to config
|
1136
1161
|
|
1162
|
+
##### **SSO Authentication (OAuth, SAML, Google/Microsoft Login)**
|
1163
|
+
|
1164
|
+
SSO authentication is complex because it involves external identity providers and multi-step flows. CursorFlow handles this by capturing the final authenticated state.
|
1165
|
+
|
1166
|
+
**The SSO Challenge:**
|
1167
|
+
- Involves external domains (accounts.google.com, login.microsoftonline.com, etc.)
|
1168
|
+
- Complex token exchanges and redirects
|
1169
|
+
- CSRF tokens and state parameters
|
1170
|
+
- May use multiple cookies across domains
|
1171
|
+
|
1172
|
+
**Solution: Capture After Manual Login**
|
1173
|
+
|
1174
|
+
CursorFlow provides a helper to capture your authenticated state after manually logging in:
|
1175
|
+
|
1176
|
+
**Step 1: Login manually in Chrome**
|
1177
|
+
```bash
|
1178
|
+
# Open your app and complete the SSO login manually
|
1179
|
+
# This handles all the OAuth redirects, token exchanges, etc.
|
1180
|
+
```
|
1181
|
+
|
1182
|
+
**Step 2: Capture authentication state**
|
1183
|
+
```bash
|
1184
|
+
# Capture all cookies and storage from your logged-in session
|
1185
|
+
cursorflow capture-auth --base-url http://localhost:3000 \
|
1186
|
+
--path /dashboard \
|
1187
|
+
--output sso-auth.json
|
1188
|
+
|
1189
|
+
# Use system Chrome for better visibility (recommended for macOS)
|
1190
|
+
cursorflow capture-auth --base-url http://localhost:3000 \
|
1191
|
+
--path /dashboard \
|
1192
|
+
--browser chrome \
|
1193
|
+
--output sso-auth.json
|
1194
|
+
|
1195
|
+
# This opens a browser, lets you login, then captures:
|
1196
|
+
# - All cookies (including third-party cookies if needed)
|
1197
|
+
# - localStorage state
|
1198
|
+
# - sessionStorage state
|
1199
|
+
# - Any tokens or auth data
|
1200
|
+
```
|
1201
|
+
|
1202
|
+
**Command Options:**
|
1203
|
+
- `--base-url`: Your application URL
|
1204
|
+
- `--path`: Page to navigate to after login (default: `/`)
|
1205
|
+
- `--output`: File to save auth state (default: `auth-capture.json`)
|
1206
|
+
- `--browser`: Browser to use - `chromium`, `chrome`, or `firefox` (default: `chromium`)
|
1207
|
+
- `--wait`: Maximum seconds to wait for login (default: `60`)
|
1208
|
+
|
1209
|
+
**Browser Visibility:**
|
1210
|
+
- Use `--browser chrome` on macOS for better window visibility
|
1211
|
+
- Browser opens maximized in headed mode
|
1212
|
+
- If you don't see it, check other desktop spaces or behind windows
|
1213
|
+
|
1214
|
+
**Step 3: Use captured auth in config**
|
1215
|
+
```json
|
1216
|
+
{
|
1217
|
+
"base_url": "http://localhost:3000",
|
1218
|
+
"auth": {
|
1219
|
+
"method": "cookies",
|
1220
|
+
"cookies": [
|
1221
|
+
// Automatically populated from capture-auth
|
1222
|
+
{
|
1223
|
+
"name": "auth_token",
|
1224
|
+
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
1225
|
+
"domain": "yourapp.com",
|
1226
|
+
"path": "/",
|
1227
|
+
"httpOnly": true,
|
1228
|
+
"secure": true
|
1229
|
+
},
|
1230
|
+
{
|
1231
|
+
"name": "refresh_token",
|
1232
|
+
"value": "abc123...",
|
1233
|
+
"domain": "yourapp.com",
|
1234
|
+
"path": "/",
|
1235
|
+
"httpOnly": true,
|
1236
|
+
"secure": true
|
1237
|
+
}
|
1238
|
+
]
|
1239
|
+
}
|
1240
|
+
}
|
1241
|
+
```
|
1242
|
+
|
1243
|
+
**Alternative: Manual Cookie Extraction**
|
1244
|
+
|
1245
|
+
If `capture-auth` is not available, extract cookies manually:
|
1246
|
+
|
1247
|
+
**For Google SSO:**
|
1248
|
+
```bash
|
1249
|
+
# 1. Login via Google in Chrome
|
1250
|
+
# 2. DevTools (F12) → Application → Cookies
|
1251
|
+
# 3. Look for cookies from BOTH domains:
|
1252
|
+
# - yourapp.com (your application cookies)
|
1253
|
+
# - accounts.google.com (Google auth cookies, if needed)
|
1254
|
+
# 4. Copy all authentication-related cookies:
|
1255
|
+
```
|
1256
|
+
|
1257
|
+
**For Microsoft/Azure AD SSO:**
|
1258
|
+
```bash
|
1259
|
+
# Same process, look for:
|
1260
|
+
# - yourapp.com cookies
|
1261
|
+
# - login.microsoftonline.com cookies (if needed)
|
1262
|
+
# - Any cookies with names like: auth_token, id_token, access_token
|
1263
|
+
```
|
1264
|
+
|
1265
|
+
**For Okta/Auth0:**
|
1266
|
+
```bash
|
1267
|
+
# Look for cookies like:
|
1268
|
+
# - okta-oauth-redirect-params
|
1269
|
+
# - okta-oauth-state
|
1270
|
+
# - sid (session ID)
|
1271
|
+
# - dt (device token)
|
1272
|
+
```
|
1273
|
+
|
1274
|
+
**Complete cookie capture example:**
|
1275
|
+
```json
|
1276
|
+
{
|
1277
|
+
"auth": {
|
1278
|
+
"method": "cookies",
|
1279
|
+
"cookies": [
|
1280
|
+
{
|
1281
|
+
"name": "appSession",
|
1282
|
+
"value": "long-base64-encoded-value...",
|
1283
|
+
"domain": "yourapp.com",
|
1284
|
+
"path": "/",
|
1285
|
+
"httpOnly": true,
|
1286
|
+
"secure": true,
|
1287
|
+
"sameSite": "Lax"
|
1288
|
+
},
|
1289
|
+
{
|
1290
|
+
"name": "identity.token",
|
1291
|
+
"value": "another-long-token...",
|
1292
|
+
"domain": "yourapp.com",
|
1293
|
+
"path": "/",
|
1294
|
+
"httpOnly": false,
|
1295
|
+
"secure": true,
|
1296
|
+
"sameSite": "None"
|
1297
|
+
}
|
1298
|
+
]
|
1299
|
+
}
|
1300
|
+
}
|
1301
|
+
```
|
1302
|
+
|
1303
|
+
**SSO Best Practices:**
|
1304
|
+
|
1305
|
+
1. **Capture all cookies**: SSO often uses multiple cookies
|
1306
|
+
2. **Check localStorage**: Some SSO solutions store tokens in localStorage
|
1307
|
+
3. **Watch for expiration**: SSO tokens typically expire (1 hour - 24 hours)
|
1308
|
+
4. **Test token validity**:
|
1309
|
+
```bash
|
1310
|
+
cursorflow test --use-session "sso-user" --path /dashboard
|
1311
|
+
# If fails, capture fresh session
|
1312
|
+
```
|
1313
|
+
|
1314
|
+
5. **Multi-domain considerations**: Some SSO requires cookies on multiple domains
|
1315
|
+
```json
|
1316
|
+
{
|
1317
|
+
"auth": {
|
1318
|
+
"method": "cookies",
|
1319
|
+
"cookies": [
|
1320
|
+
{"name": "app_session", "domain": "yourapp.com", "value": "..."},
|
1321
|
+
{"name": "sso_token", "domain": "sso.yourapp.com", "value": "..."}
|
1322
|
+
]
|
1323
|
+
}
|
1324
|
+
}
|
1325
|
+
```
|
1326
|
+
|
1327
|
+
**Refreshing SSO Tokens:**
|
1328
|
+
|
1329
|
+
SSO tokens expire. When they do:
|
1330
|
+
```bash
|
1331
|
+
# 1. Clear old session
|
1332
|
+
cursorflow sessions delete "sso-user"
|
1333
|
+
|
1334
|
+
# 2. Manually login again in Chrome
|
1335
|
+
|
1336
|
+
# 3. Capture new auth state
|
1337
|
+
cursorflow capture-auth --base-url http://localhost:3000 \
|
1338
|
+
--path /dashboard \
|
1339
|
+
--output sso-auth-refreshed.json
|
1340
|
+
|
1341
|
+
# 4. Update config with new tokens
|
1342
|
+
```
|
1343
|
+
|
1344
|
+
**Programmatic SSO (Advanced):**
|
1345
|
+
|
1346
|
+
For automated SSO without manual login, you need service account credentials from your identity provider. This is complex and varies by provider - consult your SSO provider's documentation for headless authentication flows.
|
1347
|
+
|
1137
1348
|
##### **Environment-Specific Auth**
|
1138
1349
|
|
1139
1350
|
Different credentials for local/staging/production:
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "cursorflow"
|
7
|
-
version = "2.7.
|
7
|
+
version = "2.7.9"
|
8
8
|
description = "🔥 Complete page intelligence for AI-driven development with Hot Reload Intelligence - captures DOM, network, console, performance, HMR events, and comprehensive page analysis"
|
9
9
|
authors = [
|
10
10
|
{name = "GeekWarrior Development", email = "rbush@cooltheory.com"}
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|