wafer-cli 0.2.24__tar.gz → 0.2.25__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.
Files changed (70) hide show
  1. wafer_cli-0.2.25/PKG-INFO +107 -0
  2. wafer_cli-0.2.25/README.md +89 -0
  3. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/pyproject.toml +3 -2
  4. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/tests/test_analytics.py +2 -2
  5. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/tests/test_billing.py +15 -15
  6. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/GUIDE.md +1 -1
  7. wafer_cli-0.2.25/wafer/agent_defaults.py +42 -0
  8. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/billing.py +6 -6
  9. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/cli.py +454 -86
  10. wafer_cli-0.2.25/wafer/cli_instructions.py +143 -0
  11. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/corpus.py +7 -1
  12. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/evaluate.py +13 -6
  13. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/kernel_scope.py +1 -1
  14. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/ncu_analyze.py +1 -1
  15. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/nsys_analyze.py +1 -1
  16. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/skills/wafer-guide/SKILL.md +22 -6
  17. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/ssh_keys.py +6 -6
  18. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/templates/ask_docs.py +1 -1
  19. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/templates/optimize_kernel.py +1 -1
  20. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/templates/optimize_kernelbench.py +17 -62
  21. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/templates/trace_analyze.py +1 -1
  22. wafer_cli-0.2.25/wafer/tests/test_eval_cli_parity.py +199 -0
  23. wafer_cli-0.2.25/wafer/trace_compare.py +183 -0
  24. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/wevin_cli.py +68 -9
  25. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/workspaces.py +8 -8
  26. wafer_cli-0.2.25/wafer_cli.egg-info/PKG-INFO +107 -0
  27. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer_cli.egg-info/SOURCES.txt +4 -0
  28. wafer_cli-0.2.24/PKG-INFO +0 -16
  29. wafer_cli-0.2.24/README.md +0 -242
  30. wafer_cli-0.2.24/wafer_cli.egg-info/PKG-INFO +0 -16
  31. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/setup.cfg +0 -0
  32. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/tests/test_auth.py +0 -0
  33. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/tests/test_cli_coverage.py +0 -0
  34. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/tests/test_cli_parity_integration.py +0 -0
  35. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/tests/test_config_integration.py +0 -0
  36. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/tests/test_file_operations_integration.py +0 -0
  37. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/tests/test_kernel_scope_cli.py +0 -0
  38. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/tests/test_nsys_analyze.py +0 -0
  39. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/tests/test_nsys_profile.py +0 -0
  40. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/tests/test_output.py +0 -0
  41. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/tests/test_rocprof_compute_integration.py +0 -0
  42. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/tests/test_skill_commands.py +0 -0
  43. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/tests/test_ssh_integration.py +0 -0
  44. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/tests/test_targets_ops.py +0 -0
  45. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/tests/test_wevin_cli.py +0 -0
  46. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/tests/test_workflow_integration.py +0 -0
  47. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/__init__.py +0 -0
  48. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/analytics.py +0 -0
  49. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/api_client.py +0 -0
  50. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/auth.py +0 -0
  51. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/autotuner.py +0 -0
  52. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/config.py +0 -0
  53. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/global_config.py +0 -0
  54. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/gpu_run.py +0 -0
  55. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/inference.py +0 -0
  56. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/nsys_profile.py +0 -0
  57. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/output.py +0 -0
  58. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/problems.py +0 -0
  59. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/rocprof_compute.py +0 -0
  60. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/rocprof_sdk.py +0 -0
  61. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/rocprof_systems.py +0 -0
  62. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/target_lock.py +0 -0
  63. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/targets.py +0 -0
  64. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/targets_ops.py +0 -0
  65. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/templates/__init__.py +0 -0
  66. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer/tracelens.py +0 -0
  67. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer_cli.egg-info/dependency_links.txt +0 -0
  68. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer_cli.egg-info/entry_points.txt +0 -0
  69. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer_cli.egg-info/requires.txt +0 -0
  70. {wafer_cli-0.2.24 → wafer_cli-0.2.25}/wafer_cli.egg-info/top_level.txt +0 -0
@@ -0,0 +1,107 @@
1
+ Metadata-Version: 2.4
2
+ Name: wafer-cli
3
+ Version: 0.2.25
4
+ Summary: CLI for running GPU workloads, managing remote workspaces, and evaluating/optimizing kernels
5
+ Requires-Python: >=3.11
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: typer>=0.12.0
8
+ Requires-Dist: trio>=0.24.0
9
+ Requires-Dist: trio-asyncio>=0.15.0
10
+ Requires-Dist: wafer-core>=0.1.0
11
+ Requires-Dist: perfetto>=0.16.0
12
+ Requires-Dist: posthog>=3.0.0
13
+ Provides-Extra: dev
14
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
15
+ Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
16
+ Requires-Dist: diff-cover>=8.0.0; extra == "dev"
17
+ Requires-Dist: ruff>=0.4.0; extra == "dev"
18
+
19
+ # Wafer CLI
20
+
21
+ Wafer CLI gives coding agents direct access to GPU docs, trace analysis, and remote kernel evaluation.
22
+ It helps you develop and optimize GPU kernels even when you are not working on a machine with a GPU.
23
+
24
+ ## Key features
25
+
26
+ - Query GPU documentation with citations
27
+ - Analyze GPU traces and profiles
28
+ - Evaluate kernels on remote GPUs for correctness and performance
29
+ - Run commands on GPU targets (remote or local)
30
+ - Manage persistent workspaces
31
+
32
+ ## Quick start
33
+
34
+ ```bash
35
+ uv tool install wafer-cli
36
+ wafer login
37
+ wafer remote-run -- nvidia-smi
38
+ ```
39
+
40
+ ## Common commands
41
+
42
+ ```bash
43
+ wafer workspaces list
44
+ wafer workspaces create my-workspace --wait
45
+ wafer agent -t ask-docs --corpus cuda "What causes shared memory bank conflicts?"
46
+ wafer agent -t trace-analyze --args trace=./profile.ncu-rep "Why is this kernel slow?"
47
+ wafer evaluate --impl kernel.py --reference ref.py --test-cases tests.json --benchmark
48
+ wafer nvidia ncu analyze profile.ncu-rep
49
+ wafer corpus list
50
+ ```
51
+
52
+ ## Typical workflows
53
+
54
+ ### Query GPU documentation
55
+
56
+ Download a documentation corpus and ask questions with citations.
57
+
58
+ ```bash
59
+ wafer corpus download cuda
60
+ wafer agent -t ask-docs --corpus cuda "What causes shared memory bank conflicts?"
61
+ ```
62
+
63
+ ### Analyze performance traces
64
+
65
+ Use the trace analysis template or query trace data directly.
66
+
67
+ ```bash
68
+ wafer agent -t trace-analyze --args trace=./profile.ncu-rep "Why is this kernel slow?"
69
+ wafer nvidia perfetto query trace.json \
70
+ "SELECT name, dur/1e6 as ms FROM slice WHERE cat='kernel' ORDER BY dur DESC LIMIT 10"
71
+ ```
72
+
73
+ ### Evaluate kernels on remote GPUs
74
+
75
+ Run correctness and performance checks on a remote target.
76
+
77
+ ```bash
78
+ wafer evaluate \
79
+ --impl ./kernel.py \
80
+ --reference ./reference.py \
81
+ --test-cases ./tests.json \
82
+ --benchmark
83
+ ```
84
+
85
+ ### Run commands on a remote GPU
86
+
87
+ ```bash
88
+ wafer remote-run -- nvidia-smi
89
+ wafer remote-run --upload-dir ./my_code -- python3 train.py
90
+ ```
91
+
92
+ ### Manage workspaces
93
+
94
+ ```bash
95
+ wafer workspaces list
96
+ wafer workspaces create my-workspace --wait
97
+ wafer workspaces ssh <workspace-id>
98
+ wafer workspaces delete <workspace-id>
99
+ ```
100
+
101
+ ## Install the CLI skill (optional)
102
+
103
+ ```bash
104
+ wafer skill install
105
+ # or
106
+ wafer skill install -t <claude/codex>
107
+ ```
@@ -0,0 +1,89 @@
1
+ # Wafer CLI
2
+
3
+ Wafer CLI gives coding agents direct access to GPU docs, trace analysis, and remote kernel evaluation.
4
+ It helps you develop and optimize GPU kernels even when you are not working on a machine with a GPU.
5
+
6
+ ## Key features
7
+
8
+ - Query GPU documentation with citations
9
+ - Analyze GPU traces and profiles
10
+ - Evaluate kernels on remote GPUs for correctness and performance
11
+ - Run commands on GPU targets (remote or local)
12
+ - Manage persistent workspaces
13
+
14
+ ## Quick start
15
+
16
+ ```bash
17
+ uv tool install wafer-cli
18
+ wafer login
19
+ wafer remote-run -- nvidia-smi
20
+ ```
21
+
22
+ ## Common commands
23
+
24
+ ```bash
25
+ wafer workspaces list
26
+ wafer workspaces create my-workspace --wait
27
+ wafer agent -t ask-docs --corpus cuda "What causes shared memory bank conflicts?"
28
+ wafer agent -t trace-analyze --args trace=./profile.ncu-rep "Why is this kernel slow?"
29
+ wafer evaluate --impl kernel.py --reference ref.py --test-cases tests.json --benchmark
30
+ wafer nvidia ncu analyze profile.ncu-rep
31
+ wafer corpus list
32
+ ```
33
+
34
+ ## Typical workflows
35
+
36
+ ### Query GPU documentation
37
+
38
+ Download a documentation corpus and ask questions with citations.
39
+
40
+ ```bash
41
+ wafer corpus download cuda
42
+ wafer agent -t ask-docs --corpus cuda "What causes shared memory bank conflicts?"
43
+ ```
44
+
45
+ ### Analyze performance traces
46
+
47
+ Use the trace analysis template or query trace data directly.
48
+
49
+ ```bash
50
+ wafer agent -t trace-analyze --args trace=./profile.ncu-rep "Why is this kernel slow?"
51
+ wafer nvidia perfetto query trace.json \
52
+ "SELECT name, dur/1e6 as ms FROM slice WHERE cat='kernel' ORDER BY dur DESC LIMIT 10"
53
+ ```
54
+
55
+ ### Evaluate kernels on remote GPUs
56
+
57
+ Run correctness and performance checks on a remote target.
58
+
59
+ ```bash
60
+ wafer evaluate \
61
+ --impl ./kernel.py \
62
+ --reference ./reference.py \
63
+ --test-cases ./tests.json \
64
+ --benchmark
65
+ ```
66
+
67
+ ### Run commands on a remote GPU
68
+
69
+ ```bash
70
+ wafer remote-run -- nvidia-smi
71
+ wafer remote-run --upload-dir ./my_code -- python3 train.py
72
+ ```
73
+
74
+ ### Manage workspaces
75
+
76
+ ```bash
77
+ wafer workspaces list
78
+ wafer workspaces create my-workspace --wait
79
+ wafer workspaces ssh <workspace-id>
80
+ wafer workspaces delete <workspace-id>
81
+ ```
82
+
83
+ ## Install the CLI skill (optional)
84
+
85
+ ```bash
86
+ wafer skill install
87
+ # or
88
+ wafer skill install -t <claude/codex>
89
+ ```
@@ -1,7 +1,8 @@
1
1
  [project]
2
2
  name = "wafer-cli"
3
- version = "0.2.24"
4
- description = "CLI tool for running commands on remote GPUs and GPU kernel optimization agent"
3
+ version = "0.2.25"
4
+ description = "CLI for running GPU workloads, managing remote workspaces, and evaluating/optimizing kernels"
5
+ readme = "README.md"
5
6
  requires-python = ">=3.11"
6
7
  dependencies = [
7
8
  "typer>=0.12.0",
@@ -467,7 +467,7 @@ class TestLoginLogoutAnalytics:
467
467
  patch("wafer.analytics.track_login") as mock_track_login, \
468
468
  patch("wafer.analytics.init_analytics", return_value=True):
469
469
 
470
- runner.invoke(app, ["login", "--token", "test-token"])
470
+ runner.invoke(app, ["auth", "login", "--token", "test-token"])
471
471
 
472
472
  # track_login should be called
473
473
  mock_track_login.assert_called_once_with("test-user-id", "test@example.com")
@@ -484,7 +484,7 @@ class TestLoginLogoutAnalytics:
484
484
  patch("wafer.analytics.track_logout") as mock_track_logout, \
485
485
  patch("wafer.analytics.init_analytics", return_value=True):
486
486
 
487
- result = runner.invoke(app, ["logout"])
487
+ result = runner.invoke(app, ["auth", "logout"])
488
488
 
489
489
  assert result.exit_code == 0
490
490
  mock_track_logout.assert_called_once()
@@ -210,7 +210,7 @@ class TestBillingUsageCommand:
210
210
  )
211
211
  mock_client.return_value.__enter__.return_value.get.return_value = mock_response
212
212
 
213
- result = runner.invoke(app, ["billing"])
213
+ result = runner.invoke(app, ["config", "billing"])
214
214
 
215
215
  assert result.exit_code != 0
216
216
  assert "login" in result.output.lower()
@@ -242,7 +242,7 @@ class TestBillingUsageCommand:
242
242
  mock_response.raise_for_status.return_value = None
243
243
  mock_client.return_value.__enter__.return_value.get.return_value = mock_response
244
244
 
245
- result = runner.invoke(app, ["billing", "--json"])
245
+ result = runner.invoke(app, ["config", "billing", "--json"])
246
246
 
247
247
  assert result.exit_code == 0
248
248
  data = json.loads(result.stdout)
@@ -275,7 +275,7 @@ class TestBillingUsageCommand:
275
275
  mock_response.raise_for_status.return_value = None
276
276
  mock_client.return_value.__enter__.return_value.get.return_value = mock_response
277
277
 
278
- result = runner.invoke(app, ["billing"])
278
+ result = runner.invoke(app, ["config", "billing"])
279
279
 
280
280
  assert result.exit_code == 0
281
281
  assert "Pro" in result.output
@@ -294,7 +294,7 @@ class TestBillingUsageCommand:
294
294
  httpx.RequestError("Connection failed")
295
295
  )
296
296
 
297
- result = runner.invoke(app, ["billing"])
297
+ result = runner.invoke(app, ["config", "billing"])
298
298
 
299
299
  assert result.exit_code != 0
300
300
  assert "error" in result.output.lower() or "reach" in result.output.lower()
@@ -317,7 +317,7 @@ class TestBillingTopupCommand:
317
317
  )
318
318
  mock_client.return_value.__enter__.return_value.post.return_value = mock_response
319
319
 
320
- result = runner.invoke(app, ["billing", "topup"])
320
+ result = runner.invoke(app, ["config", "billing", "topup"])
321
321
 
322
322
  assert result.exit_code != 0
323
323
  assert "login" in result.output.lower()
@@ -343,7 +343,7 @@ class TestBillingTopupCommand:
343
343
  mock_client.return_value.__enter__.return_value.post.return_value = mock_response
344
344
 
345
345
  with patch("webbrowser.open") as mock_browser:
346
- result = runner.invoke(app, ["billing", "topup"])
346
+ result = runner.invoke(app, ["config", "billing", "topup"])
347
347
 
348
348
  assert result.exit_code == 0
349
349
  # Verify $25 = 2500 cents was sent
@@ -372,7 +372,7 @@ class TestBillingTopupCommand:
372
372
  mock_client.return_value.__enter__.return_value.post.return_value = mock_response
373
373
 
374
374
  with patch("webbrowser.open") as mock_browser:
375
- result = runner.invoke(app, ["billing", "topup", "100"])
375
+ result = runner.invoke(app, ["config", "billing", "topup", "100"])
376
376
 
377
377
  assert result.exit_code == 0
378
378
  call_args = mock_client.return_value.__enter__.return_value.post.call_args
@@ -381,14 +381,14 @@ class TestBillingTopupCommand:
381
381
 
382
382
  def test_amount_below_minimum(self) -> None:
383
383
  """Amount below $10 should error."""
384
- result = runner.invoke(app, ["billing", "topup", "5"])
384
+ result = runner.invoke(app, ["config", "billing", "topup", "5"])
385
385
 
386
386
  assert result.exit_code != 0
387
387
  assert "10" in result.output # Should mention minimum
388
388
 
389
389
  def test_amount_above_maximum(self) -> None:
390
390
  """Amount above $500 should error."""
391
- result = runner.invoke(app, ["billing", "topup", "600"])
391
+ result = runner.invoke(app, ["config", "billing", "topup", "600"])
392
392
 
393
393
  assert result.exit_code != 0
394
394
  assert "500" in result.output # Should mention maximum
@@ -410,7 +410,7 @@ class TestBillingTopupCommand:
410
410
  )
411
411
  mock_client.return_value.__enter__.return_value.post.return_value = mock_response
412
412
 
413
- result = runner.invoke(app, ["billing", "topup"])
413
+ result = runner.invoke(app, ["config", "billing", "topup"])
414
414
 
415
415
  assert result.exit_code != 0
416
416
  assert "upgrade" in result.output.lower() or "portal" in result.output.lower()
@@ -436,7 +436,7 @@ class TestBillingTopupCommand:
436
436
  mock_client.return_value.__enter__.return_value.post.return_value = mock_response
437
437
 
438
438
  with patch("webbrowser.open") as mock_browser:
439
- result = runner.invoke(app, ["billing", "topup", "--no-browser"])
439
+ result = runner.invoke(app, ["config", "billing", "topup", "--no-browser"])
440
440
 
441
441
  assert result.exit_code == 0
442
442
  assert "https://checkout.stripe.com/test" in result.output
@@ -460,7 +460,7 @@ class TestBillingPortalCommand:
460
460
  )
461
461
  mock_client.return_value.__enter__.return_value.post.return_value = mock_response
462
462
 
463
- result = runner.invoke(app, ["billing", "portal"])
463
+ result = runner.invoke(app, ["config", "billing", "portal"])
464
464
 
465
465
  assert result.exit_code != 0
466
466
  assert "login" in result.output.lower()
@@ -483,7 +483,7 @@ class TestBillingPortalCommand:
483
483
  mock_client.return_value.__enter__.return_value.post.return_value = mock_response
484
484
 
485
485
  with patch("webbrowser.open") as mock_browser:
486
- result = runner.invoke(app, ["billing", "portal"])
486
+ result = runner.invoke(app, ["config", "billing", "portal"])
487
487
 
488
488
  assert result.exit_code == 0
489
489
  mock_browser.assert_called_once_with("https://billing.stripe.com/test")
@@ -506,7 +506,7 @@ class TestBillingPortalCommand:
506
506
  mock_client.return_value.__enter__.return_value.post.return_value = mock_response
507
507
 
508
508
  with patch("webbrowser.open") as mock_browser:
509
- result = runner.invoke(app, ["billing", "portal", "--no-browser"])
509
+ result = runner.invoke(app, ["config", "billing", "portal", "--no-browser"])
510
510
 
511
511
  assert result.exit_code == 0
512
512
  assert "https://billing.stripe.com/test" in result.output
@@ -528,4 +528,4 @@ class TestInsufficientCreditsError:
528
528
  message = _friendly_error(402, '{"detail": "Insufficient credits"}', "test-workspace")
529
529
 
530
530
  assert "credit" in message.lower()
531
- assert "wafer billing" in message.lower()
531
+ assert "wafer config billing" in message.lower()
@@ -7,7 +7,7 @@ GPU development primitives for LLM agents.
7
7
  Run code on cloud GPUs instantly with workspaces:
8
8
 
9
9
  ```bash
10
- wafer login # One-time auth
10
+ wafer auth login # One-time auth
11
11
  wafer workspaces create dev --gpu B200 # Create workspace (NVIDIA B200)
12
12
  wafer workspaces exec dev -- python -c "import torch; print(torch.cuda.get_device_name(0))"
13
13
  wafer workspaces sync dev ./my-project # Sync files
@@ -0,0 +1,42 @@
1
+ """Shared agent defaults for kernel optimization tasks.
2
+
3
+ Single source of truth for bash allowlists and enabled tools used by both:
4
+ - CLI templates (apps/wafer-cli/wafer/templates/optimize_kernelbench.py)
5
+ - Eval configs (research/evals/optimize_kernelbench_eval/.../base_config.py)
6
+
7
+ Import from here instead of defining your own copy.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ # Tools available to the agent (coding environment tools)
13
+ ENABLED_TOOLS: list[str] = ["read", "write", "edit", "glob", "grep", "bash"]
14
+
15
+ # Bash commands allowed for kernel optimization agents.
16
+ # Uses prefix matching — "wafer evaluate" also allows "wafer evaluate kernelbench".
17
+ KERNELBENCH_BASH_ALLOWLIST: list[str] = [
18
+ # Kernel evaluation
19
+ "wafer evaluate",
20
+ # Profiling — AMD
21
+ "wafer amd rocprof-compute",
22
+ "wafer amd rocprof-sdk",
23
+ "wafer amd rocprof-systems",
24
+ # Profiling — NVIDIA
25
+ "wafer nvidia ncu",
26
+ "wafer nvidia nsys",
27
+ # Analysis
28
+ "wafer compiler-analyze",
29
+ # Sub-agents
30
+ "wafer agent -t ask-docs",
31
+ # General utilities
32
+ "python",
33
+ "python3",
34
+ "timeout",
35
+ "ls",
36
+ "cat",
37
+ "head",
38
+ "tail",
39
+ "wc",
40
+ "pwd",
41
+ "which",
42
+ ]
@@ -1,6 +1,6 @@
1
1
  """Billing CLI - Manage credits and subscription.
2
2
 
3
- This module provides the implementation for the `wafer billing` subcommand.
3
+ This module provides the implementation for the `wafer config billing` subcommand.
4
4
  """
5
5
 
6
6
  import json
@@ -126,7 +126,7 @@ def format_usage_text(usage: dict) -> str:
126
126
  lines.extend([
127
127
  "",
128
128
  "Upgrade to Pro for hardware counters and credit topups:",
129
- " wafer billing portal",
129
+ " wafer config billing portal",
130
130
  ])
131
131
 
132
132
  return "\n".join(lines)
@@ -153,7 +153,7 @@ def get_usage(json_output: bool = False) -> str:
153
153
  usage = response.json()
154
154
  except httpx.HTTPStatusError as e:
155
155
  if e.response.status_code == 401:
156
- raise RuntimeError("Not authenticated. Run: wafer login") from e
156
+ raise RuntimeError("Not authenticated. Run: wafer auth login") from e
157
157
  raise RuntimeError(f"API error: {e.response.status_code} - {e.response.text}") from e
158
158
  except httpx.RequestError as e:
159
159
  raise RuntimeError(f"Could not reach API: {e}") from e
@@ -188,7 +188,7 @@ def create_topup(amount_cents: int) -> dict:
188
188
  return response.json()
189
189
  except httpx.HTTPStatusError as e:
190
190
  if e.response.status_code == 401:
191
- raise RuntimeError("Not authenticated. Run: wafer login") from e
191
+ raise RuntimeError("Not authenticated. Run: wafer auth login") from e
192
192
  if e.response.status_code == 400:
193
193
  # Invalid amount
194
194
  try:
@@ -200,7 +200,7 @@ def create_topup(amount_cents: int) -> dict:
200
200
  # Start tier or other restriction
201
201
  raise RuntimeError(
202
202
  "Topup not available for your subscription tier.\n"
203
- "Upgrade your subscription first: wafer billing portal"
203
+ "Upgrade your subscription first: wafer config billing portal"
204
204
  ) from e
205
205
  if e.response.status_code == 503:
206
206
  raise RuntimeError("Billing service temporarily unavailable. Please try again later.") from e
@@ -227,7 +227,7 @@ def get_portal_url() -> dict:
227
227
  return response.json()
228
228
  except httpx.HTTPStatusError as e:
229
229
  if e.response.status_code == 401:
230
- raise RuntimeError("Not authenticated. Run: wafer login") from e
230
+ raise RuntimeError("Not authenticated. Run: wafer auth login") from e
231
231
  raise RuntimeError(f"API error: {e.response.status_code} - {e.response.text}") from e
232
232
  except httpx.RequestError as e:
233
233
  raise RuntimeError(f"Could not reach API: {e}") from e