cursorflow 2.7.7__py3-none-any.whl → 2.7.8__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 +152 -0
- cursorflow/rules/cursorflow-usage.mdc +51 -0
- {cursorflow-2.7.7.dist-info → cursorflow-2.7.8.dist-info}/METADATA +14 -1
- {cursorflow-2.7.7.dist-info → cursorflow-2.7.8.dist-info}/RECORD +8 -8
- {cursorflow-2.7.7.dist-info → cursorflow-2.7.8.dist-info}/WHEEL +0 -0
- {cursorflow-2.7.7.dist-info → cursorflow-2.7.8.dist-info}/entry_points.txt +0 -0
- {cursorflow-2.7.7.dist-info → cursorflow-2.7.8.dist-info}/licenses/LICENSE +0 -0
- {cursorflow-2.7.7.dist-info → cursorflow-2.7.8.dist-info}/top_level.txt +0 -0
cursorflow/cli.py
CHANGED
@@ -1116,6 +1116,158 @@ 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
|
+
def capture_auth(base_url, path, output, wait):
|
1125
|
+
"""
|
1126
|
+
Capture authentication state after manual SSO/OAuth login
|
1127
|
+
|
1128
|
+
Opens a browser, waits for you to complete SSO login manually,
|
1129
|
+
then captures all cookies, localStorage, and sessionStorage.
|
1130
|
+
Perfect for Google/Microsoft/Okta SSO authentication.
|
1131
|
+
|
1132
|
+
\b
|
1133
|
+
Process:
|
1134
|
+
1. Browser opens to your app
|
1135
|
+
2. Complete SSO login manually (Google, Microsoft, Okta, etc.)
|
1136
|
+
3. Navigate to a protected page (e.g., /dashboard)
|
1137
|
+
4. CursorFlow captures all auth state
|
1138
|
+
5. Auth state saved to JSON file
|
1139
|
+
6. Use in .cursorflow/config.json as cookie authentication
|
1140
|
+
|
1141
|
+
\b
|
1142
|
+
Examples:
|
1143
|
+
# Capture Google SSO auth
|
1144
|
+
cursorflow capture-auth --base-url http://localhost:3000 --path /dashboard
|
1145
|
+
|
1146
|
+
# Capture with custom wait time
|
1147
|
+
cursorflow capture-auth -u http://localhost:3000 -p /dashboard --wait 120
|
1148
|
+
|
1149
|
+
# Save to custom file
|
1150
|
+
cursorflow capture-auth -u http://localhost:3000 --output google-sso.json
|
1151
|
+
"""
|
1152
|
+
console.print(f"\n🔐 SSO Authentication Capture")
|
1153
|
+
console.print(f"📍 Base URL: [cyan]{base_url}[/cyan]")
|
1154
|
+
console.print(f"🎯 Target path: [cyan]{path}[/cyan]")
|
1155
|
+
console.print(f"⏱️ Wait time: [yellow]{wait}[/yellow] seconds")
|
1156
|
+
console.print(f"📄 Output file: [green]{output}[/green]\n")
|
1157
|
+
|
1158
|
+
console.print("📋 [bold]Instructions:[/bold]")
|
1159
|
+
console.print(" 1. Browser will open to your application")
|
1160
|
+
console.print(" 2. [yellow]Complete SSO login manually[/yellow] (Google, Microsoft, Okta, etc.)")
|
1161
|
+
console.print(" 3. Navigate to a protected page (e.g., /dashboard)")
|
1162
|
+
console.print(" 4. [green]Press Enter[/green] when fully logged in")
|
1163
|
+
console.print(" 5. CursorFlow will capture all auth state\n")
|
1164
|
+
|
1165
|
+
input("Press Enter to open browser and start capture...")
|
1166
|
+
|
1167
|
+
try:
|
1168
|
+
from playwright.async_api import async_playwright
|
1169
|
+
import json
|
1170
|
+
|
1171
|
+
async def capture_process():
|
1172
|
+
async with async_playwright() as p:
|
1173
|
+
# Launch browser in HEADED mode (user needs to interact)
|
1174
|
+
browser = await p.chromium.launch(headless=False)
|
1175
|
+
context = await browser.new_context()
|
1176
|
+
page = await context.new_page()
|
1177
|
+
|
1178
|
+
console.print(f"\n🌐 Opening browser to: [cyan]{base_url}[/cyan]")
|
1179
|
+
await page.goto(base_url)
|
1180
|
+
|
1181
|
+
console.print(f"\n⏳ [yellow]Complete your SSO login in the browser...[/yellow]")
|
1182
|
+
console.print(f" Waiting up to {wait} seconds...")
|
1183
|
+
console.print(f" [bold]Press Enter in this terminal when logged in and on {path}[/bold]\n")
|
1184
|
+
|
1185
|
+
# Wait for user to complete login
|
1186
|
+
import sys
|
1187
|
+
import select
|
1188
|
+
|
1189
|
+
# Simple blocking wait for Enter key
|
1190
|
+
input("Press Enter after completing login... ")
|
1191
|
+
|
1192
|
+
# Navigate to target path to ensure we're at the right place
|
1193
|
+
if path != '/':
|
1194
|
+
console.print(f"📍 Navigating to: [cyan]{path}[/cyan]")
|
1195
|
+
await page.goto(f"{base_url.rstrip('/')}{path}")
|
1196
|
+
await page.wait_for_load_state("networkidle")
|
1197
|
+
|
1198
|
+
console.print("\n📸 Capturing authentication state...")
|
1199
|
+
|
1200
|
+
# Capture all authentication data
|
1201
|
+
storage_state = await context.storage_state()
|
1202
|
+
|
1203
|
+
# Get localStorage
|
1204
|
+
local_storage = await page.evaluate("""
|
1205
|
+
() => {
|
1206
|
+
const storage = {};
|
1207
|
+
for (let i = 0; i < localStorage.length; i++) {
|
1208
|
+
const key = localStorage.key(i);
|
1209
|
+
storage[key] = localStorage.getItem(key);
|
1210
|
+
}
|
1211
|
+
return storage;
|
1212
|
+
}
|
1213
|
+
""")
|
1214
|
+
|
1215
|
+
# Get sessionStorage
|
1216
|
+
session_storage = await page.evaluate("""
|
1217
|
+
() => {
|
1218
|
+
const storage = {};
|
1219
|
+
for (let i = 0; i < sessionStorage.length; i++) {
|
1220
|
+
const key = sessionStorage.key(i);
|
1221
|
+
storage[key] = sessionStorage.getItem(key);
|
1222
|
+
}
|
1223
|
+
return storage;
|
1224
|
+
}
|
1225
|
+
""")
|
1226
|
+
|
1227
|
+
# Organize captured data
|
1228
|
+
auth_data = {
|
1229
|
+
"captured_at": time.strftime("%Y-%m-%d %H:%M:%S"),
|
1230
|
+
"base_url": base_url,
|
1231
|
+
"current_url": page.url,
|
1232
|
+
"method": "cookies",
|
1233
|
+
"cookies": storage_state.get("cookies", []),
|
1234
|
+
"localStorage": local_storage,
|
1235
|
+
"sessionStorage": session_storage,
|
1236
|
+
"usage_instructions": {
|
1237
|
+
"1": "Copy the 'cookies' array below",
|
1238
|
+
"2": "Add to .cursorflow/config.json under auth.cookies",
|
1239
|
+
"3": "Set auth.method to 'cookies'",
|
1240
|
+
"4": "Use with: cursorflow test --use-session <name>"
|
1241
|
+
}
|
1242
|
+
}
|
1243
|
+
|
1244
|
+
# Save to file
|
1245
|
+
output_path = Path(output)
|
1246
|
+
with open(output_path, 'w') as f:
|
1247
|
+
json.dump(auth_data, f, indent=2)
|
1248
|
+
|
1249
|
+
console.print(f"\n✅ Authentication state captured!")
|
1250
|
+
console.print(f"📄 Saved to: [green]{output_path.absolute()}[/green]")
|
1251
|
+
console.print(f"🍪 Captured {len(auth_data['cookies'])} cookies")
|
1252
|
+
console.print(f"💾 localStorage: {len(local_storage)} items")
|
1253
|
+
console.print(f"💾 sessionStorage: {len(session_storage)} items")
|
1254
|
+
|
1255
|
+
console.print(f"\n📋 [bold]Next steps:[/bold]")
|
1256
|
+
console.print(f" 1. Open: [cyan]{output}[/cyan]")
|
1257
|
+
console.print(f" 2. Copy the 'cookies' array")
|
1258
|
+
console.print(f" 3. Add to .cursorflow/config.json:")
|
1259
|
+
console.print(f'\n {{\n "auth": {{\n "method": "cookies",\n "cookies": [... paste here ...]\n }}\n }}\n')
|
1260
|
+
console.print(f" 4. Test with: [cyan]cursorflow test --use-session sso-user[/cyan]\n")
|
1261
|
+
|
1262
|
+
await browser.close()
|
1263
|
+
|
1264
|
+
asyncio.run(capture_process())
|
1265
|
+
|
1266
|
+
except KeyboardInterrupt:
|
1267
|
+
console.print("\n[yellow]⚠️ Capture cancelled by user[/yellow]")
|
1268
|
+
except Exception as e:
|
1269
|
+
console.print(f"[red]❌ Error capturing auth: {escape(str(e))}[/red]")
|
1270
|
+
|
1119
1271
|
@main.command()
|
1120
1272
|
@click.option('--base-url', '-u', required=True)
|
1121
1273
|
@click.option('--path', '-p', default='/', help='Path to navigate to')
|
@@ -1076,6 +1076,45 @@ 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
|
+
--output google-sso.json
|
1088
|
+
|
1089
|
+
# Browser opens, you complete SSO login, CursorFlow captures cookies
|
1090
|
+
|
1091
|
+
# 2. Copy cookies from google-sso.json to .cursorflow/config.json:
|
1092
|
+
{
|
1093
|
+
"auth": {
|
1094
|
+
"method": "cookies",
|
1095
|
+
"cookies": [/* paste from google-sso.json */]
|
1096
|
+
}
|
1097
|
+
}
|
1098
|
+
|
1099
|
+
# 3. Use captured auth
|
1100
|
+
cursorflow test --use-session "sso-user" --path /dashboard
|
1101
|
+
```
|
1102
|
+
|
1103
|
+
**SSO providers supported:**
|
1104
|
+
- Google OAuth
|
1105
|
+
- Microsoft Azure AD
|
1106
|
+
- Okta
|
1107
|
+
- Auth0
|
1108
|
+
- Any OAuth/SAML provider
|
1109
|
+
|
1110
|
+
**When SSO tokens expire:**
|
1111
|
+
```bash
|
1112
|
+
# Re-capture auth (SSO tokens typically expire in 1-24 hours)
|
1113
|
+
cursorflow capture-auth --base-url http://localhost:3000 \
|
1114
|
+
--path /dashboard \
|
1115
|
+
--output sso-refreshed.json
|
1116
|
+
```
|
1117
|
+
|
1079
1118
|
### **Troubleshooting Auth**
|
1080
1119
|
|
1081
1120
|
**Auth failing?**
|
@@ -1100,6 +1139,18 @@ cat .cursorflow/sessions/user_session.json
|
|
1100
1139
|
cursorflow test --use-session "user" --fresh-session
|
1101
1140
|
```
|
1102
1141
|
|
1142
|
+
**SSO not working?**
|
1143
|
+
```bash
|
1144
|
+
# Re-capture auth state
|
1145
|
+
cursorflow capture-auth --base-url http://localhost:3000 --path /dashboard
|
1146
|
+
|
1147
|
+
# Check if localStorage has tokens (some SSO stores tokens there)
|
1148
|
+
cat auth-capture.json | grep localStorage
|
1149
|
+
|
1150
|
+
# Test immediately after capture
|
1151
|
+
cursorflow test --use-session "sso-user" --path /dashboard
|
1152
|
+
```
|
1153
|
+
|
1103
1154
|
## Best Practices
|
1104
1155
|
|
1105
1156
|
### **🔥 Hot Reload CSS Iteration Best Practices**
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: cursorflow
|
3
|
-
Version: 2.7.
|
3
|
+
Version: 2.7.8
|
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,19 @@ 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
|
+
--output google-sso.json
|
188
|
+
|
189
|
+
# Use captured auth
|
190
|
+
# (Copy cookies from google-sso.json to .cursorflow/config.json)
|
191
|
+
cursorflow test --use-session "sso-user" --path /dashboard
|
192
|
+
```
|
180
193
|
|
181
194
|
**See:** [Complete Authentication Guide](docs/user/USAGE_GUIDE.md#authentication--session-management)
|
182
195
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
cursorflow/__init__.py,sha256=2V9xzG2tYxVWOTmSw2v9Jdbr7lSrMi_y2SMUMuNZdvw,2990
|
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=
|
4
|
+
cursorflow/cli.py,sha256=Tt3I9d6SFplJjM4UPdxXklGjh1kt511-irE_jqDAw_A,87342
|
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
|
@@ -33,10 +33,10 @@ cursorflow/log_sources/local_file.py,sha256=GVnhsaifIdc41twXwbxRM9-fBeRDsknDpk5I
|
|
33
33
|
cursorflow/log_sources/ssh_remote.py,sha256=_Kwh0bhRpKgq-0c98oaX2hN6h9cT-wCHlqY5NiWVCoY,8388
|
34
34
|
cursorflow/rules/__init__.py,sha256=gPcA-IkhXj03sl7cvZV0wwo7CtEkcyuKs4y0F5oQbqE,458
|
35
35
|
cursorflow/rules/cursorflow-installation.mdc,sha256=D55pzzDPAVVbE3gAtKPUGoT-2fvB-FI2l6yrTdzUIEo,10208
|
36
|
-
cursorflow/rules/cursorflow-usage.mdc,sha256=
|
37
|
-
cursorflow-2.7.
|
38
|
-
cursorflow-2.7.
|
39
|
-
cursorflow-2.7.
|
40
|
-
cursorflow-2.7.
|
41
|
-
cursorflow-2.7.
|
42
|
-
cursorflow-2.7.
|
36
|
+
cursorflow/rules/cursorflow-usage.mdc,sha256=wv7EOeybBUmgYGux9yE_8SWAgoNYa5DfbT5sC44WNOU,38768
|
37
|
+
cursorflow-2.7.8.dist-info/licenses/LICENSE,sha256=e4QbjAsj3bW-xgQOvQelr8sGLYDoqc48k6cKgCr_pBU,1080
|
38
|
+
cursorflow-2.7.8.dist-info/METADATA,sha256=aCPcMbLb-PrXzfCqebLSdwjW17Fs33sRVteAa81uRlM,21237
|
39
|
+
cursorflow-2.7.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
40
|
+
cursorflow-2.7.8.dist-info/entry_points.txt,sha256=-Ed_n4Uff7wClEtWS-Py6xmQabecB9f0QAOjX0w7ljA,51
|
41
|
+
cursorflow-2.7.8.dist-info/top_level.txt,sha256=t1UZwRyZP4u-ng2CEcNHmk_ZT4ibQxoihB2IjTF7ovc,11
|
42
|
+
cursorflow-2.7.8.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|