wafer-cli 0.2.16__py3-none-any.whl → 0.2.18__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 +7 -0
- wafer/evaluate.py +2 -1
- wafer/workspaces.py +59 -8
- {wafer_cli-0.2.16.dist-info → wafer_cli-0.2.18.dist-info}/METADATA +1 -1
- {wafer_cli-0.2.16.dist-info → wafer_cli-0.2.18.dist-info}/RECORD +8 -8
- {wafer_cli-0.2.16.dist-info → wafer_cli-0.2.18.dist-info}/WHEEL +0 -0
- {wafer_cli-0.2.16.dist-info → wafer_cli-0.2.18.dist-info}/entry_points.txt +0 -0
- {wafer_cli-0.2.16.dist-info → wafer_cli-0.2.18.dist-info}/top_level.txt +0 -0
wafer/auth.py
CHANGED
|
@@ -191,6 +191,10 @@ def get_valid_token() -> str | None:
|
|
|
191
191
|
if e.response.status_code != 401:
|
|
192
192
|
# Not an auth error, re-raise
|
|
193
193
|
raise
|
|
194
|
+
except httpx.RequestError:
|
|
195
|
+
# Network error (timeout, connection refused, DNS failure, etc.)
|
|
196
|
+
# Cannot verify token - return None to trigger re-login prompt
|
|
197
|
+
return None
|
|
194
198
|
|
|
195
199
|
# Token expired, try refresh
|
|
196
200
|
if not creds.refresh_token:
|
|
@@ -203,6 +207,9 @@ def get_valid_token() -> str | None:
|
|
|
203
207
|
except httpx.HTTPStatusError:
|
|
204
208
|
# Refresh failed, need to re-login
|
|
205
209
|
return None
|
|
210
|
+
except httpx.RequestError:
|
|
211
|
+
# Network error during refresh - return None to trigger re-login prompt
|
|
212
|
+
return None
|
|
206
213
|
|
|
207
214
|
|
|
208
215
|
def _find_free_port() -> int:
|
wafer/evaluate.py
CHANGED
|
@@ -354,7 +354,8 @@ def _build_docker_pip_install_cmd(target: BaremetalTarget | VMTarget) -> str:
|
|
|
354
354
|
)
|
|
355
355
|
|
|
356
356
|
# Install uv (fast, reliable) - use pip3 for compatibility
|
|
357
|
-
|
|
357
|
+
# Use --break-system-packages for Python 3.12+ with PEP 668 externally managed environments
|
|
358
|
+
commands.append("pip3 install --break-system-packages uv")
|
|
358
359
|
|
|
359
360
|
# Install torch with custom index if specified (like Modal's two-phase install)
|
|
360
361
|
# Use --system --break-system-packages to install to container's Python
|
wafer/workspaces.py
CHANGED
|
@@ -13,7 +13,7 @@ import httpx
|
|
|
13
13
|
from .api_client import get_api_url
|
|
14
14
|
from .auth import get_auth_headers
|
|
15
15
|
|
|
16
|
-
VALID_STATUSES = {"creating", "running"}
|
|
16
|
+
VALID_STATUSES = {"creating", "running", "error"}
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def _get_client() -> tuple[str, dict[str, str]]:
|
|
@@ -211,17 +211,39 @@ def list_workspaces(json_output: bool = False) -> str:
|
|
|
211
211
|
lines = ["Workspaces:", ""]
|
|
212
212
|
for ws in workspaces:
|
|
213
213
|
status = ws.get("status", "unknown")
|
|
214
|
-
status_icon = {"running": "●", "creating": "◐"}.get(status, "?")
|
|
214
|
+
status_icon = {"running": "●", "creating": "◐", "error": "✗"}.get(status, "?")
|
|
215
215
|
lines.append(f" {status_icon} {ws['name']} ({ws['id']})")
|
|
216
216
|
lines.append(f" GPU: {ws.get('gpu_type', 'N/A')} | Image: {ws.get('image', 'N/A')}")
|
|
217
|
-
|
|
217
|
+
|
|
218
|
+
if status == "error":
|
|
219
|
+
lines.append(
|
|
220
|
+
f" Status: Provisioning failed. Delete and recreate: wafer workspaces delete {ws['name']}"
|
|
221
|
+
)
|
|
222
|
+
elif ws.get("ssh_host") and ws.get("ssh_port") and ws.get("ssh_user"):
|
|
223
|
+
ssh_line = f" SSH: ssh -p {ws['ssh_port']} {ws['ssh_user']}@{ws['ssh_host']}"
|
|
224
|
+
if status == "creating":
|
|
225
|
+
ssh_line += " (finalizing...)"
|
|
226
|
+
lines.append(ssh_line)
|
|
227
|
+
elif status == "running":
|
|
218
228
|
lines.append(
|
|
219
|
-
f" SSH:
|
|
229
|
+
f" Status: Running but SSH not ready. Try: wafer workspaces delete {ws['name']} && wafer workspaces create {ws['name']} --wait"
|
|
220
230
|
)
|
|
221
231
|
else:
|
|
222
|
-
lines.append(" SSH: Not ready (
|
|
232
|
+
lines.append(" SSH: Not ready (workspace is still creating)")
|
|
223
233
|
lines.append("")
|
|
224
234
|
|
|
235
|
+
# Add SSH tip for users with running workspaces
|
|
236
|
+
has_running_with_ssh = any(
|
|
237
|
+
ws.get("status") == "running" and ws.get("ssh_host")
|
|
238
|
+
for ws in workspaces
|
|
239
|
+
)
|
|
240
|
+
if has_running_with_ssh:
|
|
241
|
+
lines.append("Tip: SSH directly for interactive work. 'exec' is for quick commands only.")
|
|
242
|
+
|
|
243
|
+
has_error = any(ws.get("status") == "error" for ws in workspaces)
|
|
244
|
+
if has_error:
|
|
245
|
+
lines.append("Note: Error workspaces are auto-cleaned after 12 hours.")
|
|
246
|
+
|
|
225
247
|
return "\n".join(lines)
|
|
226
248
|
|
|
227
249
|
|
|
@@ -441,6 +463,12 @@ def sync_files(
|
|
|
441
463
|
f"Workspace {workspace_id} has invalid status '{workspace_status}'. "
|
|
442
464
|
f"Valid statuses: {VALID_STATUSES}"
|
|
443
465
|
)
|
|
466
|
+
if workspace_status == "error":
|
|
467
|
+
raise RuntimeError(
|
|
468
|
+
f"Workspace provisioning failed. Delete and recreate:\n"
|
|
469
|
+
f" wafer workspaces delete {workspace_id}\n"
|
|
470
|
+
f" wafer workspaces create {ws.get('name', workspace_id)} --wait"
|
|
471
|
+
)
|
|
444
472
|
if workspace_status != "running":
|
|
445
473
|
raise RuntimeError(
|
|
446
474
|
f"Workspace is {workspace_status}. Wait for it to be running before syncing."
|
|
@@ -448,9 +476,14 @@ def sync_files(
|
|
|
448
476
|
ssh_host = ws.get("ssh_host")
|
|
449
477
|
ssh_port = ws.get("ssh_port")
|
|
450
478
|
ssh_user = ws.get("ssh_user")
|
|
451
|
-
|
|
479
|
+
if not ssh_host or not ssh_port or not ssh_user:
|
|
480
|
+
# Workspace is running but SSH credentials are missing - unusual state
|
|
481
|
+
raise RuntimeError(
|
|
482
|
+
f"Workspace is running but SSH not ready.\n"
|
|
483
|
+
f" Delete and recreate: wafer workspaces delete {workspace_id}\n"
|
|
484
|
+
f" Then: wafer workspaces create {ws.get('name', workspace_id)} --wait"
|
|
485
|
+
)
|
|
452
486
|
assert isinstance(ssh_port, int) and ssh_port > 0, "Workspace missing valid ssh_port"
|
|
453
|
-
assert ssh_user, "Workspace missing ssh_user"
|
|
454
487
|
|
|
455
488
|
# Build rsync command
|
|
456
489
|
# -a: archive mode (preserves permissions, etc.)
|
|
@@ -607,16 +640,34 @@ def get_workspace(workspace_id: str, json_output: bool = False) -> str:
|
|
|
607
640
|
f" Last Used: {workspace.get('last_used_at', 'N/A')}",
|
|
608
641
|
]
|
|
609
642
|
|
|
610
|
-
if
|
|
643
|
+
if status == "error":
|
|
644
|
+
lines.extend([
|
|
645
|
+
"",
|
|
646
|
+
"Provisioning failed. Delete and recreate:",
|
|
647
|
+
f" wafer workspaces delete {workspace['name']}",
|
|
648
|
+
f" wafer workspaces create {workspace['name']} --wait",
|
|
649
|
+
"",
|
|
650
|
+
"Note: Error workspaces are auto-cleaned after 12 hours.",
|
|
651
|
+
])
|
|
652
|
+
elif workspace.get("ssh_host"):
|
|
611
653
|
lines.extend([
|
|
612
654
|
"",
|
|
613
655
|
"SSH Info:",
|
|
614
656
|
f" Host: {workspace['ssh_host']}",
|
|
615
657
|
f" Port: {workspace.get('ssh_port', 22)}",
|
|
616
658
|
f" User: {workspace.get('ssh_user', 'root')}",
|
|
659
|
+
"",
|
|
660
|
+
"Tip: SSH directly for interactive work. 'exec' is for quick commands only.",
|
|
617
661
|
])
|
|
618
662
|
elif status == "creating":
|
|
619
663
|
lines.extend(["", "SSH: available once workspace is running"])
|
|
664
|
+
elif status == "running":
|
|
665
|
+
# Running but no SSH credentials - unusual state
|
|
666
|
+
lines.extend([
|
|
667
|
+
"",
|
|
668
|
+
"Status: Running but SSH not ready.",
|
|
669
|
+
f" Delete and recreate: wafer workspaces delete {workspace['name']}",
|
|
670
|
+
])
|
|
620
671
|
|
|
621
672
|
return "\n".join(lines)
|
|
622
673
|
|
|
@@ -2,13 +2,13 @@ wafer/GUIDE.md,sha256=G6P4aFZslEXiHmVjtTB3_OIpGK5d1tSiqxtawASVUZg,3588
|
|
|
2
2
|
wafer/__init__.py,sha256=kBM_ONCpU6UUMBOH8Tmg4A88sNFnbaD59o61cJs-uYM,90
|
|
3
3
|
wafer/analytics.py,sha256=qLY6Z16usVHFD8TCv7XBuz7l47vXVdXk-qhOzA-hW_8,8179
|
|
4
4
|
wafer/api_client.py,sha256=i_Az2b2llC3DSW8yOL-BKqa7LSKuxOr8hSN40s-oQXY,6313
|
|
5
|
-
wafer/auth.py,sha256=
|
|
5
|
+
wafer/auth.py,sha256=dwss_se5P-FFc9IN38q4kh_dBrA6k-CguDBkivgcdj0,14003
|
|
6
6
|
wafer/autotuner.py,sha256=41WYP41pTDvMijv2h42vm89bcHtDMJXObDlWmn6xpFU,44416
|
|
7
7
|
wafer/billing.py,sha256=jbLB2lI4_9f2KD8uEFDi_ixLlowe5hasC0TIZJyIXRg,7163
|
|
8
8
|
wafer/cli.py,sha256=lBBTQCcmKREqZDOQh27qSq8i6NedjHW5oh1JiuT9aho,254241
|
|
9
9
|
wafer/config.py,sha256=h5Eo9_yfWqWGoPNdVQikI9GoZVUeysunSYiixf1mKcw,3411
|
|
10
10
|
wafer/corpus.py,sha256=x5aFhCsTSAtgzFG9AMFpqq92Ej63mXofL-vvvpjj1sM,12913
|
|
11
|
-
wafer/evaluate.py,sha256=
|
|
11
|
+
wafer/evaluate.py,sha256=s1NszUBtxdWRonbi8YR3XWfCiCjNm14g2Pp1lu4kmtY,176125
|
|
12
12
|
wafer/global_config.py,sha256=fhaR_RU3ufMksDmOohH1OLeQ0JT0SDW1hEip_zaP75k,11345
|
|
13
13
|
wafer/gpu_run.py,sha256=TwqXy72T7f2I7e6n5WWod3xgxCPnDhU0BgLsB4CUoQY,9716
|
|
14
14
|
wafer/inference.py,sha256=tZCO5i05FKY27ewis3CSBHFBeFbXY3xwj0DSjdoMY9s,4314
|
|
@@ -27,15 +27,15 @@ wafer/targets.py,sha256=9r-iRWoKSH5cQl1LcamaX-T7cNVOg99ngIm_hlRk-qU,26922
|
|
|
27
27
|
wafer/targets_ops.py,sha256=jN1oIBx0mutxRNE9xpIc7SaBxPkVmOyus2eqn0kEKNI,21475
|
|
28
28
|
wafer/tracelens.py,sha256=g9ZIeFyNojZn4uTd3skPqIrRiL7aMJOz_-GOd3aiyy4,7998
|
|
29
29
|
wafer/wevin_cli.py,sha256=vF3GNH-qWXO4hAlXaDg98VZpS4uFexVUp94BHsJjjMU,22179
|
|
30
|
-
wafer/workspaces.py,sha256=
|
|
30
|
+
wafer/workspaces.py,sha256=iUdioK7kA3z_gOTMNVDn9Q87c6qpkdXF4bOhJWkUPg8,32375
|
|
31
31
|
wafer/skills/wafer-guide/SKILL.md,sha256=KWetJw2TVTbz11_nzqazqOJWWRlbHRFShs4sOoreiWo,3255
|
|
32
32
|
wafer/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
33
|
wafer/templates/ask_docs.py,sha256=Lxs-faz9v5m4Qa4NjF2X_lE8KwM9ES9MNJkxo7ep56o,2256
|
|
34
34
|
wafer/templates/optimize_kernel.py,sha256=u6AL7Q3uttqlnBLzcoFdsiPq5lV2TV3bgqwCYYlK9gk,2357
|
|
35
35
|
wafer/templates/optimize_kernelbench.py,sha256=aoOA13zWEl89r6QW03xF9NKxQ7j4mWe9rwua6-mlr4Y,4780
|
|
36
36
|
wafer/templates/trace_analyze.py,sha256=XE1VqzVkIUsZbXF8EzQdDYgg-AZEYAOFpr6B_vnRELc,2880
|
|
37
|
-
wafer_cli-0.2.
|
|
38
|
-
wafer_cli-0.2.
|
|
39
|
-
wafer_cli-0.2.
|
|
40
|
-
wafer_cli-0.2.
|
|
41
|
-
wafer_cli-0.2.
|
|
37
|
+
wafer_cli-0.2.18.dist-info/METADATA,sha256=reFoNYKvPiYo1PO25LUKissdgm-UsaIem763Pme_H0E,560
|
|
38
|
+
wafer_cli-0.2.18.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
39
|
+
wafer_cli-0.2.18.dist-info/entry_points.txt,sha256=WqB7hB__WhtPY8y1cO2sZiUz7fCq6Ik-usAigpeFvWE,41
|
|
40
|
+
wafer_cli-0.2.18.dist-info/top_level.txt,sha256=2MK1IVMWfpLL8BZCQ3E9aG6L6L666gSA_teYlwan4fs,6
|
|
41
|
+
wafer_cli-0.2.18.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|