wafer-cli 0.2.14__py3-none-any.whl → 0.2.30__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/global_config.py CHANGED
@@ -234,7 +234,20 @@ def get_supabase_anon_key() -> str:
234
234
 
235
235
  The anon key is public and used for client-side auth operations
236
236
  like token refresh.
237
+
238
+ If SUPABASE_URL is set via env var, infer the matching anon key
239
+ from the built-in environments. Otherwise, use the config file's environment.
237
240
  """
241
+ supabase_url = get_supabase_url()
242
+
243
+ # If SUPABASE_URL was set via env var, find matching environment
244
+ if os.environ.get("SUPABASE_URL"):
245
+ # Check built-in environments to find matching Supabase URL
246
+ for env_name, env in BUILTIN_ENVIRONMENTS.items():
247
+ if env.supabase_url == supabase_url:
248
+ return env.supabase_anon_key
249
+
250
+ # Otherwise, use config file's environment
238
251
  return load_global_config().get_api_environment().supabase_anon_key
239
252
 
240
253
 
wafer/kernel_scope.py CHANGED
@@ -95,7 +95,7 @@ def analyze_command(
95
95
  if not api_url or not auth_headers:
96
96
  raise RuntimeError(
97
97
  "API authentication required for .co file analysis. "
98
- "Run 'wafer login' first."
98
+ "Run 'wafer auth login' first."
99
99
  )
100
100
  result = analyze_code_object(target_path, api_url, auth_headers)
101
101
  # ISA files - use kernel_index parameter
wafer/ncu_analyze.py CHANGED
@@ -520,7 +520,7 @@ def _analyze_remote_api(
520
520
 
521
521
  except httpx.HTTPStatusError as e:
522
522
  if e.response.status_code == 401:
523
- raise RuntimeError("Not authenticated. Run: wafer login") from e
523
+ raise RuntimeError("Not authenticated. Run: wafer auth login") from e
524
524
  raise RuntimeError(f"API error: {e.response.status_code} - {e.response.text}") from e
525
525
  except httpx.RequestError as e:
526
526
  raise RuntimeError(f"Could not reach API: {e}") from e
wafer/nsys_analyze.py CHANGED
@@ -844,7 +844,7 @@ def _analyze_remote_api(
844
844
 
845
845
  except httpx.HTTPStatusError as e:
846
846
  if e.response.status_code == 401:
847
- raise RuntimeError("Not authenticated. Run: wafer login") from e
847
+ raise RuntimeError("Not authenticated. Run: wafer auth login") from e
848
848
  raise RuntimeError(f"API error: {e.response.status_code} - {e.response.text}") from e
849
849
  except httpx.RequestError as e:
850
850
  raise RuntimeError(f"Could not reach API: {e}") from e
@@ -16,7 +16,7 @@ Before using Wafer CLI commands, install the tool:
16
16
  uv tool install wafer-cli
17
17
 
18
18
  # Authenticate (one-time setup)
19
- wafer login
19
+ wafer auth login
20
20
 
21
21
  ```
22
22
 
@@ -71,15 +71,31 @@ Test correctness and measure speedup against a reference:
71
71
  wafer evaluate make-template ./my-kernel
72
72
  # Creates: kernel.py, reference.py, test_cases.json
73
73
 
74
- # Run evaluation on a configured target
75
- wafer evaluate \
74
+ # test_cases.json format:
75
+ # [{"name": "small", "n": 1024, "seed": 42}, {"name": "large", "n": 1048576, "seed": 42}]
76
+ # Each dict is passed as **kwargs to generate_input() in reference.py
77
+
78
+ # Run correctness check (GPUMode functional format)
79
+ wafer evaluate gpumode \
76
80
  --impl ./my-kernel/kernel.py \
77
81
  --reference ./my-kernel/reference.py \
78
82
  --test-cases ./my-kernel/test_cases.json \
79
83
  --target <target-name>
80
84
 
81
- # With profiling
82
- wafer evaluate ... --profile
85
+ # Run correctness + benchmark (measures speedup vs reference)
86
+ wafer evaluate gpumode \
87
+ --impl ./my-kernel/kernel.py \
88
+ --reference ./my-kernel/reference.py \
89
+ --test-cases ./my-kernel/test_cases.json \
90
+ --target <target-name> --benchmark
91
+
92
+ # Run with defensive timing (detects evaluation hacking)
93
+ wafer evaluate gpumode ... --benchmark --defensive
94
+
95
+ # KernelBench format (ModelNew class)
96
+ wafer evaluate kernelbench \
97
+ --impl my_kernel.py --reference problem.py \
98
+ --target <target-name> --stages all
83
99
  ```
84
100
 
85
101
  ### 4. AI-Assisted Optimization
@@ -126,4 +142,4 @@ wafer config targets init runpod # RunPod cloud GPUs
126
142
  wafer config targets init digitalocean # DigitalOcean AMD GPUs
127
143
  ```
128
144
 
129
- Then use: `wafer evaluate --target <name> ...`
145
+ Then use: `wafer evaluate gpumode --target <name> ...`
wafer/specs_cli.py ADDED
@@ -0,0 +1,157 @@
1
+ """CLI commands for wafer specs — TargetSpec TOML management.
2
+
3
+ These are the local config commands (no API calls).
4
+ Registered as: wafer specs list|show|add|remove|default|init
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from pathlib import Path
10
+
11
+ import typer
12
+
13
+ specs_app = typer.Typer(
14
+ help="""Manage GPU target specs (provisioning blueprints).
15
+
16
+ Specs define how to access or provision GPUs. They are TOML files in ~/.wafer/specs/.
17
+
18
+ wafer specs list # List all specs
19
+ wafer specs show runpod-mi300x # Show one spec
20
+ wafer specs add /path/to/spec.toml # Add from file
21
+ wafer specs remove old-target # Remove a spec
22
+ wafer specs default runpod-mi300x # Set default
23
+
24
+ To create a new spec interactively:
25
+ wafer config targets init ssh # (legacy, still works)
26
+ wafer config targets init runpod
27
+ """
28
+ )
29
+
30
+
31
+ @specs_app.command("list")
32
+ def specs_list() -> None:
33
+ """List all configured specs.
34
+
35
+ Example:
36
+ wafer specs list
37
+ """
38
+ from wafer_core.targets.spec_store import list_spec_names, load_spec
39
+
40
+ from .targets import get_default_target
41
+
42
+ names = list_spec_names()
43
+ default = get_default_target()
44
+
45
+ if not names:
46
+ typer.echo("No specs configured.")
47
+ typer.echo("Add one with: wafer specs add <path/to/spec.toml>")
48
+ typer.echo("Or interactively: wafer config targets init ssh")
49
+ return
50
+
51
+ typer.echo("Configured specs:")
52
+ for name in names:
53
+ marker = " (default)" if name == default else ""
54
+ try:
55
+ spec = load_spec(name)
56
+ type_name = type(spec).__name__.replace("Target", "")
57
+ typer.echo(f" {name}{marker} [{type_name}] gpu={spec.gpu_type}")
58
+ except Exception as e:
59
+ typer.echo(f" {name}{marker} [error: {e}]")
60
+
61
+
62
+ @specs_app.command("show")
63
+ def specs_show(
64
+ name: str = typer.Argument(..., help="Spec name"),
65
+ ) -> None:
66
+ """Show details for a spec.
67
+
68
+ Example:
69
+ wafer specs show runpod-mi300x
70
+ """
71
+ from wafer_core.targets.spec_store import load_spec
72
+
73
+ from .targets import get_target_info
74
+
75
+ try:
76
+ spec = load_spec(name)
77
+ except FileNotFoundError:
78
+ typer.echo(f"Spec not found: {name}", err=True)
79
+ raise typer.Exit(1) from None
80
+
81
+ typer.echo(f"Spec: {name}")
82
+ for key, value in get_target_info(spec).items():
83
+ typer.echo(f" {key}: {value}")
84
+
85
+
86
+ @specs_app.command("add")
87
+ def specs_add(
88
+ file_path: Path = typer.Argument(..., help="Path to TOML spec file"),
89
+ ) -> None:
90
+ """Add a spec from a TOML file.
91
+
92
+ Example:
93
+ wafer specs add ./my-target.toml
94
+ """
95
+ import tomllib
96
+
97
+ from wafer_core.targets.spec_store import parse_spec, save_spec
98
+
99
+ if not file_path.exists():
100
+ typer.echo(f"File not found: {file_path}", err=True)
101
+ raise typer.Exit(1) from None
102
+
103
+ try:
104
+ with open(file_path, "rb") as f:
105
+ data = tomllib.load(f)
106
+ spec = parse_spec(data)
107
+ save_spec(spec)
108
+ typer.echo(f"Added spec: {spec.name}")
109
+ except Exception as e:
110
+ typer.echo(f"Error: {e}", err=True)
111
+ raise typer.Exit(1) from None
112
+
113
+
114
+ @specs_app.command("remove")
115
+ def specs_remove(
116
+ name: str = typer.Argument(..., help="Spec name to remove"),
117
+ force: bool = typer.Option(False, "--force", "-f", help="Skip confirmation"),
118
+ ) -> None:
119
+ """Remove a spec.
120
+
121
+ Example:
122
+ wafer specs remove old-target
123
+ """
124
+ from wafer_core.targets.spec_store import remove_spec
125
+
126
+ if not force:
127
+ confirm = typer.confirm(f"Remove spec '{name}'?")
128
+ if not confirm:
129
+ return
130
+
131
+ try:
132
+ remove_spec(name)
133
+ typer.echo(f"Removed spec: {name}")
134
+ except FileNotFoundError:
135
+ typer.echo(f"Spec not found: {name}", err=True)
136
+ raise typer.Exit(1) from None
137
+
138
+
139
+ @specs_app.command("default")
140
+ def specs_default(
141
+ name: str = typer.Argument(..., help="Spec name to set as default"),
142
+ ) -> None:
143
+ """Set the default spec.
144
+
145
+ Example:
146
+ wafer specs default runpod-mi300x
147
+ """
148
+ from wafer_core.targets.spec_store import list_spec_names
149
+
150
+ from .targets import set_default_target
151
+
152
+ if name not in list_spec_names():
153
+ typer.echo(f"Spec not found: {name}", err=True)
154
+ raise typer.Exit(1) from None
155
+
156
+ set_default_target(name)
157
+ typer.echo(f"Default spec set to: {name}")
wafer/ssh_keys.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """SSH Keys CLI - Manage SSH public keys for workspace access.
2
2
 
3
- This module provides the implementation for the `wafer ssh-keys` subcommand.
3
+ This module provides the implementation for the `wafer config ssh-keys` subcommand.
4
4
  Users register their SSH public keys here, which are then installed in all
5
5
  workspaces they attach to (BYOK - Bring Your Own Key model).
6
6
  """
@@ -94,7 +94,7 @@ def list_ssh_keys(json_output: bool = False) -> str:
94
94
  keys = response.json()
95
95
  except httpx.HTTPStatusError as e:
96
96
  if e.response.status_code == 401:
97
- raise RuntimeError("Not authenticated. Run: wafer login") from e
97
+ raise RuntimeError("Not authenticated. Run: wafer auth login") from e
98
98
  raise RuntimeError(f"API error: {e.response.status_code} - {e.response.text}") from e
99
99
  except httpx.RequestError as e:
100
100
  raise RuntimeError(f"Could not reach API: {e}") from e
@@ -107,7 +107,7 @@ def list_ssh_keys(json_output: bool = False) -> str:
107
107
  "No SSH keys registered.\n"
108
108
  "\n"
109
109
  "Add your SSH key:\n"
110
- " wafer ssh-keys add\n"
110
+ " wafer config ssh-keys add\n"
111
111
  "\n"
112
112
  "This will auto-detect your key from ~/.ssh/"
113
113
  )
@@ -149,7 +149,7 @@ def add_ssh_key(
149
149
  " ssh-keygen -t ed25519\n"
150
150
  "\n"
151
151
  "Or specify a path:\n"
152
- " wafer ssh-keys add /path/to/key.pub"
152
+ " wafer config ssh-keys add /path/to/key.pub"
153
153
  )
154
154
  pubkey_path = detected[0]
155
155
 
@@ -202,7 +202,7 @@ def add_ssh_key(
202
202
  key_data = response.json()
203
203
  except httpx.HTTPStatusError as e:
204
204
  if e.response.status_code == 401:
205
- raise RuntimeError("Not authenticated. Run: wafer login") from e
205
+ raise RuntimeError("Not authenticated. Run: wafer auth login") from e
206
206
  if e.response.status_code == 400:
207
207
  # Parse error detail
208
208
  try:
@@ -248,7 +248,7 @@ def remove_ssh_key(key_id: str, json_output: bool = False) -> str:
248
248
  response.raise_for_status()
249
249
  except httpx.HTTPStatusError as e:
250
250
  if e.response.status_code == 401:
251
- raise RuntimeError("Not authenticated. Run: wafer login") from e
251
+ raise RuntimeError("Not authenticated. Run: wafer auth login") from e
252
252
  if e.response.status_code == 404:
253
253
  raise RuntimeError(f"SSH key not found: {key_id}") from e
254
254
  raise RuntimeError(f"API error: {e.response.status_code} - {e.response.text}") from e