wafer-cli 0.2.38__tar.gz → 0.2.39__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 (72) hide show
  1. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/PKG-INFO +1 -1
  2. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/pyproject.toml +1 -1
  3. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/agent_defaults.py +48 -1
  4. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/cli.py +52 -11
  5. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/wevin_cli.py +36 -3
  6. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer_cli.egg-info/PKG-INFO +1 -1
  7. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/README.md +0 -0
  8. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/setup.cfg +0 -0
  9. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/tests/test_analytics.py +0 -0
  10. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/tests/test_auth.py +0 -0
  11. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/tests/test_billing.py +0 -0
  12. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/tests/test_cli_coverage.py +0 -0
  13. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/tests/test_cli_parity_integration.py +0 -0
  14. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/tests/test_config_integration.py +0 -0
  15. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/tests/test_file_operations_integration.py +0 -0
  16. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/tests/test_kernel_scope_cli.py +0 -0
  17. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/tests/test_nsys_analyze.py +0 -0
  18. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/tests/test_nsys_profile.py +0 -0
  19. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/tests/test_output.py +0 -0
  20. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/tests/test_rocprof_compute_integration.py +0 -0
  21. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/tests/test_skill_commands.py +0 -0
  22. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/tests/test_ssh_integration.py +0 -0
  23. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/tests/test_targets_ops.py +0 -0
  24. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/tests/test_wevin_cli.py +0 -0
  25. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/tests/test_workflow_integration.py +0 -0
  26. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/GUIDE.md +0 -0
  27. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/__init__.py +0 -0
  28. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/analytics.py +0 -0
  29. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/api_client.py +0 -0
  30. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/auth.py +0 -0
  31. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/autotuner.py +0 -0
  32. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/baseline.py +0 -0
  33. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/billing.py +0 -0
  34. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/cli_instructions.py +0 -0
  35. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/config.py +0 -0
  36. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/corpus.py +0 -0
  37. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/evaluate.py +0 -0
  38. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/global_config.py +0 -0
  39. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/gpu_run.py +0 -0
  40. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/inference.py +0 -0
  41. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/kernel_scope.py +0 -0
  42. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/ncu_analyze.py +0 -0
  43. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/nsys_analyze.py +0 -0
  44. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/nsys_profile.py +0 -0
  45. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/output.py +0 -0
  46. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/problems.py +0 -0
  47. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/rocprof_compute.py +0 -0
  48. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/rocprof_sdk.py +0 -0
  49. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/rocprof_systems.py +0 -0
  50. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/skills/wafer-guide/SKILL.md +0 -0
  51. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/specs_cli.py +0 -0
  52. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/ssh_keys.py +0 -0
  53. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/target_lock.py +0 -0
  54. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/targets.py +0 -0
  55. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/targets_cli.py +0 -0
  56. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/targets_ops.py +0 -0
  57. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/templates/__init__.py +0 -0
  58. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/templates/aiter_optimize.py +0 -0
  59. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/templates/ask_docs.py +0 -0
  60. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/templates/optimize_kernel.py +0 -0
  61. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/templates/optimize_kernelbench.py +0 -0
  62. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/templates/optimize_vllm.py +0 -0
  63. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/templates/trace_analyze.py +0 -0
  64. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/tests/test_eval_cli_parity.py +0 -0
  65. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/trace_compare.py +0 -0
  66. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/tracelens.py +0 -0
  67. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer/workspaces.py +0 -0
  68. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer_cli.egg-info/SOURCES.txt +0 -0
  69. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer_cli.egg-info/dependency_links.txt +0 -0
  70. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer_cli.egg-info/entry_points.txt +0 -0
  71. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer_cli.egg-info/requires.txt +0 -0
  72. {wafer_cli-0.2.38 → wafer_cli-0.2.39}/wafer_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wafer-cli
3
- Version: 0.2.38
3
+ Version: 0.2.39
4
4
  Summary: CLI for running GPU workloads, managing remote workspaces, and evaluating/optimizing kernels
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "wafer-cli"
3
- version = "0.2.38"
3
+ version = "0.2.39"
4
4
  description = "CLI for running GPU workloads, managing remote workspaces, and evaluating/optimizing kernels"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -1,4 +1,4 @@
1
- """Shared agent defaults for kernel optimization tasks.
1
+ """Shared agent defaults for kernel tasks.
2
2
 
3
3
  Single source of truth for bash allowlists and enabled tools used by both:
4
4
  - CLI templates (apps/wafer-cli/wafer/templates/*.py)
@@ -195,3 +195,50 @@ VLLM_BASH_ALLOWLIST: list[str] = [
195
195
  "cd",
196
196
  "git",
197
197
  ]
198
+
199
+ # Tools available to audit agents (read-only + bash for compilation/profiling)
200
+ AUDIT_ENABLED_TOOLS: list[str] = ["read", "glob", "grep", "bash"]
201
+
202
+ # Bash commands allowed for kernel audit agents.
203
+ AUDIT_BASH_ALLOWLIST: list[str] = [
204
+ # Read-only
205
+ "ls",
206
+ "cat",
207
+ "head",
208
+ "tail",
209
+ "wc",
210
+ "find",
211
+ "grep",
212
+ "rg",
213
+ "pwd",
214
+ "tree",
215
+ "which",
216
+ "diff",
217
+ "sort",
218
+ # Filesystem
219
+ "mkdir",
220
+ # Compilation
221
+ "make",
222
+ "cmake",
223
+ "nvcc",
224
+ "hipcc",
225
+ "g++",
226
+ "gcc",
227
+ "clang",
228
+ "python",
229
+ "python3",
230
+ # Execution — allows running compiled binaries via ./path.
231
+ # Security note: the agent can already compile arbitrary code via hipcc/gcc/etc,
232
+ # so blocking ./ execution doesn't add meaningful protection.
233
+ "./",
234
+ # Profiling
235
+ "wafer evaluate",
236
+ "wafer nvidia ncu",
237
+ "wafer nvidia nsys",
238
+ "wafer amd rocprof-compute",
239
+ "wafer amd rocprof-sdk",
240
+ "wafer amd rocprof-systems",
241
+ "wafer compiler-analyze",
242
+ # Misc
243
+ "timeout",
244
+ ]
@@ -1862,6 +1862,12 @@ def kernelbench_evaluate( # noqa: PLR0913, PLR0915
1862
1862
  help="Sync files and generate eval script but don't run. "
1863
1863
  "Prints the command to run manually (useful for wrapping with rocprof, etc.)",
1864
1864
  ),
1865
+ pool_timeout: int = typer.Option(
1866
+ 600,
1867
+ "--pool-timeout",
1868
+ help="Seconds to wait for a target from the pool before failing (default: 600). "
1869
+ "Set to 0 for immediate failure if all targets are busy.",
1870
+ ),
1865
1871
  json_output: bool = typer.Option(
1866
1872
  False, "--json", help="Output as single JSON object (machine-readable)"
1867
1873
  ),
@@ -1953,14 +1959,24 @@ def kernelbench_evaluate( # noqa: PLR0913, PLR0915
1953
1959
  collector.finalize()
1954
1960
  raise typer.Exit(1) from None
1955
1961
 
1956
- collector.emit("pool_acquire", pool=pool, count=len(usable_targets))
1957
- pool_lock_context = acquire_from_pool(usable_targets)
1962
+ effective_timeout = pool_timeout if pool_timeout > 0 else None
1963
+ collector.emit("pool_acquire", pool=pool, count=len(usable_targets), timeout=pool_timeout)
1964
+ pool_lock_context = acquire_from_pool(usable_targets, timeout=effective_timeout)
1958
1965
  acquired_target = pool_lock_context.__enter__()
1959
1966
 
1960
1967
  if acquired_target is None:
1961
1968
  # Exit context manager before raising to avoid resource leak
1962
1969
  pool_lock_context.__exit__(None, None, None)
1963
- collector.set_error("pool", "AllTargetsBusy", pool=pool, targets=usable_targets)
1970
+ if pool_timeout > 0:
1971
+ collector.set_error(
1972
+ "pool",
1973
+ "AllTargetsBusy",
1974
+ pool=pool,
1975
+ targets=usable_targets,
1976
+ message=f"All targets busy after waiting {pool_timeout}s",
1977
+ )
1978
+ else:
1979
+ collector.set_error("pool", "AllTargetsBusy", pool=pool, targets=usable_targets)
1964
1980
  collector.finalize()
1965
1981
  raise typer.Exit(1)
1966
1982
 
@@ -2315,6 +2331,12 @@ def gpumode_evaluate( # noqa: PLR0913, PLR0915
2315
2331
  True, "--sync-artifacts/--no-sync-artifacts", help="Download artifacts"
2316
2332
  ),
2317
2333
  gpu_id: int | None = typer.Option(None, "--gpu-id", help="Override GPU ID"),
2334
+ pool_timeout: int = typer.Option(
2335
+ 600,
2336
+ "--pool-timeout",
2337
+ help="Seconds to wait for a target from the pool before failing (default: 600). "
2338
+ "Set to 0 for immediate failure if all targets are busy.",
2339
+ ),
2318
2340
  ) -> None:
2319
2341
  """Run kernel evaluation in GPUMode format (functional).
2320
2342
 
@@ -2394,14 +2416,21 @@ def gpumode_evaluate( # noqa: PLR0913, PLR0915
2394
2416
  typer.echo(" Run 'wafer auth status' to see which providers need setup.", err=True)
2395
2417
  raise typer.Exit(1) from None
2396
2418
 
2419
+ effective_timeout = pool_timeout if pool_timeout > 0 else None
2397
2420
  typer.echo(f"Acquiring target from pool '{pool}' ({len(usable_targets)} targets)...")
2398
- pool_lock_context = acquire_from_pool(usable_targets)
2421
+ pool_lock_context = acquire_from_pool(usable_targets, timeout=effective_timeout)
2399
2422
  acquired_target = pool_lock_context.__enter__()
2400
2423
 
2401
2424
  if acquired_target is None:
2402
2425
  # Exit context manager before raising to avoid resource leak
2403
2426
  pool_lock_context.__exit__(None, None, None)
2404
- typer.echo(f"Error: All targets in pool '{pool}' are busy", err=True)
2427
+ if pool_timeout > 0:
2428
+ typer.echo(
2429
+ f"Error: All targets in pool '{pool}' are busy (waited {pool_timeout}s)",
2430
+ err=True,
2431
+ )
2432
+ else:
2433
+ typer.echo(f"Error: All targets in pool '{pool}' are busy", err=True)
2405
2434
  typer.echo(f" Targets: {', '.join(usable_targets)}", err=True)
2406
2435
  raise typer.Exit(1)
2407
2436
 
@@ -7751,16 +7780,24 @@ def compare_analyze(
7751
7780
  "-f",
7752
7781
  help="Output format: text, text-layers, csv, csv-layers, json",
7753
7782
  ),
7754
- output: Path | None = typer.Option(None, "--output", "-o", help="Output file (default: stdout)"),
7783
+ output: Path | None = typer.Option(
7784
+ None, "--output", "-o", help="Output file (default: stdout)"
7785
+ ),
7755
7786
  phase: str = typer.Option(
7756
7787
  "all",
7757
7788
  "--phase",
7758
7789
  help="Filter by phase: all, prefill, decode",
7759
7790
  ),
7760
7791
  layers: bool = typer.Option(False, "--layers", help="Show layer-wise performance breakdown"),
7761
- all: bool = typer.Option(False, "--all", help="Show all items (no truncation for layers, operations, kernels)"),
7762
- stack_traces: bool = typer.Option(False, "--stack-traces", help="Show Python stack traces for operations"),
7763
- json: bool = typer.Option(False, "--json", hidden=True, help="Ignored (for compatibility with cliExecutor)"),
7792
+ all: bool = typer.Option(
7793
+ False, "--all", help="Show all items (no truncation for layers, operations, kernels)"
7794
+ ),
7795
+ stack_traces: bool = typer.Option(
7796
+ False, "--stack-traces", help="Show Python stack traces for operations"
7797
+ ),
7798
+ json: bool = typer.Option(
7799
+ False, "--json", hidden=True, help="Ignored (for compatibility with cliExecutor)"
7800
+ ),
7764
7801
  ) -> None:
7765
7802
  """Compare GPU traces from two platforms platforms.
7766
7803
 
@@ -7824,13 +7861,17 @@ def compare_fusion_cmd(
7824
7861
  "-f",
7825
7862
  help="Output format: text, csv, json",
7826
7863
  ),
7827
- output: Path | None = typer.Option(None, "--output", "-o", help="Output file (default: stdout)"),
7864
+ output: Path | None = typer.Option(
7865
+ None, "--output", "-o", help="Output file (default: stdout)"
7866
+ ),
7828
7867
  min_group_size: int = typer.Option(
7829
7868
  50,
7830
7869
  "--min-group-size",
7831
7870
  help="Minimum correlation group size to analyze",
7832
7871
  ),
7833
- json: bool = typer.Option(False, "--json", hidden=True, help="Ignored (for compatibility with cliExecutor)"),
7872
+ json: bool = typer.Option(
7873
+ False, "--json", hidden=True, help="Ignored (for compatibility with cliExecutor)"
7874
+ ),
7834
7875
  ) -> None:
7835
7876
  """Analyze kernel fusion differences between AMD and NVIDIA traces.
7836
7877
 
@@ -326,13 +326,28 @@ def _build_environment(
326
326
  tools_override: list[str] | None,
327
327
  corpus_path: str | None,
328
328
  no_sandbox: bool = False,
329
+ has_target: bool = False,
330
+ template_args: dict[str, str] | None = None,
329
331
  ) -> Environment:
330
- """Build a CodingEnvironment from template config."""
332
+ """Build a CodingEnvironment from template config.
333
+
334
+ Working directory priority:
335
+ 1. Template arg "dir" (--args dir=./my_project) — scopes agent to a directory
336
+ 2. corpus_path (--corpus cuda) — for doc-browsing templates
337
+ 3. Current working directory
338
+ """
331
339
  from wafer_core.environments.coding import CodingEnvironment
332
340
  from wafer_core.rollouts.templates import DANGEROUS_BASH_COMMANDS
333
341
  from wafer_core.sandbox import SandboxMode
334
342
 
335
- working_dir = Path(corpus_path) if corpus_path else Path.cwd()
343
+ # Template arg "dir" takes priority over corpus_path
344
+ dir_arg = (template_args or {}).get("dir")
345
+ if dir_arg:
346
+ working_dir = Path(dir_arg).resolve()
347
+ elif corpus_path:
348
+ working_dir = Path(corpus_path)
349
+ else:
350
+ working_dir = Path.cwd()
336
351
  resolved_tools = list(tools_override or tpl.tools)
337
352
 
338
353
  # Add skill tool if skills are enabled
@@ -340,12 +355,18 @@ def _build_environment(
340
355
  resolved_tools.append("skill")
341
356
 
342
357
  sandbox_mode = SandboxMode.DISABLED if no_sandbox else SandboxMode.ENABLED
358
+
359
+ # Enable network when a target is configured — the agent needs to reach
360
+ # remote GPUs via SSH/HTTPS. Filesystem sandbox stays enforced.
361
+ allow_network = has_target
362
+
343
363
  env: Environment = CodingEnvironment(
344
364
  working_dir=working_dir,
345
365
  enabled_tools=resolved_tools,
346
366
  bash_allowlist=tpl.bash_allowlist,
347
367
  bash_denylist=DANGEROUS_BASH_COMMANDS,
348
368
  sandbox_mode=sandbox_mode,
369
+ allow_network=allow_network,
349
370
  ) # type: ignore[assignment]
350
371
  return env
351
372
 
@@ -589,9 +610,21 @@ def main( # noqa: PLR0913, PLR0915
589
610
  # CLI args override template values
590
611
  resolved_single_turn = single_turn if single_turn is not None else tpl.single_turn
591
612
 
613
+ # Check if a default target is configured — if so, enable network access
614
+ # so the agent can reach remote GPUs via SSH/HTTPS.
615
+ has_target = False
616
+ try:
617
+ from wafer.targets import get_default_target
618
+
619
+ has_target = get_default_target() is not None
620
+ except Exception:
621
+ pass # No target configured — network stays disabled
622
+
592
623
  # Build endpoint and environment
593
624
  endpoint = _build_endpoint(tpl, model, api_base, api_key, api_key_refresh)
594
- environment = _build_environment(tpl, tools, corpus_path, no_sandbox)
625
+ environment = _build_environment(
626
+ tpl, tools, corpus_path, no_sandbox, has_target=has_target, template_args=template_args
627
+ )
595
628
 
596
629
  # Session store
597
630
  session_store = FileSessionStore()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wafer-cli
3
- Version: 0.2.38
3
+ Version: 0.2.39
4
4
  Summary: CLI for running GPU workloads, managing remote workspaces, and evaluating/optimizing kernels
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes