wafer-cli 0.2.8__py3-none-any.whl → 0.2.9__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.
- wafer/auth.py +85 -0
- wafer/cli.py +1196 -160
- wafer/evaluate.py +1171 -209
- wafer/gpu_run.py +5 -1
- wafer/kernel_scope.py +453 -0
- wafer/problems.py +357 -0
- wafer/target_lock.py +270 -0
- wafer/targets.py +490 -0
- wafer/wevin_cli.py +2 -0
- wafer/workspaces.py +53 -1
- {wafer_cli-0.2.8.dist-info → wafer_cli-0.2.9.dist-info}/METADATA +1 -1
- {wafer_cli-0.2.8.dist-info → wafer_cli-0.2.9.dist-info}/RECORD +15 -12
- {wafer_cli-0.2.8.dist-info → wafer_cli-0.2.9.dist-info}/WHEEL +0 -0
- {wafer_cli-0.2.8.dist-info → wafer_cli-0.2.9.dist-info}/entry_points.txt +0 -0
- {wafer_cli-0.2.8.dist-info → wafer_cli-0.2.9.dist-info}/top_level.txt +0 -0
wafer/auth.py
CHANGED
|
@@ -345,3 +345,88 @@ def browser_login(timeout: int = 120, port: int | None = None) -> tuple[str, str
|
|
|
345
345
|
|
|
346
346
|
server.server_close()
|
|
347
347
|
raise TimeoutError(f"No response within {timeout} seconds")
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def device_code_login(timeout: int = 600) -> tuple[str, str | None]:
|
|
351
|
+
"""Authenticate using state-based flow (no browser/port forwarding needed).
|
|
352
|
+
|
|
353
|
+
This is the SSH-friendly auth flow similar to GitHub CLI:
|
|
354
|
+
1. Request a state token from the API
|
|
355
|
+
2. Display the auth URL with state parameter
|
|
356
|
+
3. User visits URL on any device and signs in normally
|
|
357
|
+
4. Poll API until user completes authentication
|
|
358
|
+
|
|
359
|
+
Args:
|
|
360
|
+
timeout: Seconds to wait for authentication (default 600 = 10 minutes)
|
|
361
|
+
|
|
362
|
+
Returns:
|
|
363
|
+
Tuple of (access_token, refresh_token). refresh_token may be None.
|
|
364
|
+
|
|
365
|
+
Raises:
|
|
366
|
+
TimeoutError: If user doesn't authenticate within timeout
|
|
367
|
+
RuntimeError: If auth flow failed
|
|
368
|
+
"""
|
|
369
|
+
api_url = get_api_url()
|
|
370
|
+
|
|
371
|
+
# Request state and auth URL
|
|
372
|
+
with httpx.Client(timeout=10.0) as client:
|
|
373
|
+
response = client.post(f"{api_url}/v1/auth/cli-auth/start", json={})
|
|
374
|
+
response.raise_for_status()
|
|
375
|
+
data = response.json()
|
|
376
|
+
|
|
377
|
+
state = data["state"]
|
|
378
|
+
auth_url = data["auth_url"]
|
|
379
|
+
expires_in = data["expires_in"]
|
|
380
|
+
|
|
381
|
+
# Display instructions to user
|
|
382
|
+
print("\n" + "=" * 60)
|
|
383
|
+
print(" WAFER CLI - Authentication")
|
|
384
|
+
print("=" * 60)
|
|
385
|
+
print(f"\n Visit: {auth_url}")
|
|
386
|
+
print("\n Sign in with GitHub to complete authentication")
|
|
387
|
+
print("\n" + "=" * 60 + "\n")
|
|
388
|
+
|
|
389
|
+
# Poll for authentication
|
|
390
|
+
start = time.time()
|
|
391
|
+
poll_interval = 5 # Poll every 5 seconds
|
|
392
|
+
last_poll = 0.0
|
|
393
|
+
|
|
394
|
+
print("Waiting for authentication", end="", flush=True)
|
|
395
|
+
|
|
396
|
+
while time.time() - start < min(timeout, expires_in):
|
|
397
|
+
# Show progress dots
|
|
398
|
+
if time.time() - last_poll >= poll_interval:
|
|
399
|
+
print(".", end="", flush=True)
|
|
400
|
+
|
|
401
|
+
# Poll the API
|
|
402
|
+
with httpx.Client(timeout=10.0) as client:
|
|
403
|
+
try:
|
|
404
|
+
response = client.post(f"{api_url}/v1/auth/cli-auth/token", json={"state": state})
|
|
405
|
+
|
|
406
|
+
if response.status_code == 200:
|
|
407
|
+
# Success!
|
|
408
|
+
data = response.json()
|
|
409
|
+
print(f" {CHECK}\n")
|
|
410
|
+
return data["access_token"], data.get("refresh_token")
|
|
411
|
+
|
|
412
|
+
if response.status_code == 428:
|
|
413
|
+
# Still waiting
|
|
414
|
+
last_poll = time.time()
|
|
415
|
+
time.sleep(1)
|
|
416
|
+
continue
|
|
417
|
+
|
|
418
|
+
# Some other error
|
|
419
|
+
print(f" {CROSS}\n")
|
|
420
|
+
raise RuntimeError(f"CLI auth flow failed: {response.status_code} {response.text}")
|
|
421
|
+
|
|
422
|
+
except httpx.RequestError as e:
|
|
423
|
+
# Network error, retry
|
|
424
|
+
print("!", end="", flush=True)
|
|
425
|
+
last_poll = time.time()
|
|
426
|
+
time.sleep(1)
|
|
427
|
+
continue
|
|
428
|
+
|
|
429
|
+
time.sleep(0.5) # Small sleep to avoid busy loop
|
|
430
|
+
|
|
431
|
+
print(f" {CROSS}\n")
|
|
432
|
+
raise TimeoutError(f"Authentication not completed within {expires_in} seconds")
|