wafer-cli 0.2.37__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.37 → wafer_cli-0.2.39}/PKG-INFO +1 -1
  2. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/pyproject.toml +1 -1
  3. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/agent_defaults.py +48 -1
  4. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/cli.py +54 -11
  5. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/wevin_cli.py +36 -3
  6. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer_cli.egg-info/PKG-INFO +1 -1
  7. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/README.md +0 -0
  8. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/setup.cfg +0 -0
  9. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/tests/test_analytics.py +0 -0
  10. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/tests/test_auth.py +0 -0
  11. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/tests/test_billing.py +0 -0
  12. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/tests/test_cli_coverage.py +0 -0
  13. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/tests/test_cli_parity_integration.py +0 -0
  14. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/tests/test_config_integration.py +0 -0
  15. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/tests/test_file_operations_integration.py +0 -0
  16. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/tests/test_kernel_scope_cli.py +0 -0
  17. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/tests/test_nsys_analyze.py +0 -0
  18. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/tests/test_nsys_profile.py +0 -0
  19. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/tests/test_output.py +0 -0
  20. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/tests/test_rocprof_compute_integration.py +0 -0
  21. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/tests/test_skill_commands.py +0 -0
  22. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/tests/test_ssh_integration.py +0 -0
  23. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/tests/test_targets_ops.py +0 -0
  24. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/tests/test_wevin_cli.py +0 -0
  25. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/tests/test_workflow_integration.py +0 -0
  26. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/GUIDE.md +0 -0
  27. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/__init__.py +0 -0
  28. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/analytics.py +0 -0
  29. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/api_client.py +0 -0
  30. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/auth.py +0 -0
  31. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/autotuner.py +0 -0
  32. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/baseline.py +0 -0
  33. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/billing.py +0 -0
  34. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/cli_instructions.py +0 -0
  35. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/config.py +0 -0
  36. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/corpus.py +0 -0
  37. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/evaluate.py +0 -0
  38. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/global_config.py +0 -0
  39. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/gpu_run.py +0 -0
  40. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/inference.py +0 -0
  41. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/kernel_scope.py +0 -0
  42. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/ncu_analyze.py +0 -0
  43. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/nsys_analyze.py +0 -0
  44. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/nsys_profile.py +0 -0
  45. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/output.py +0 -0
  46. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/problems.py +0 -0
  47. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/rocprof_compute.py +0 -0
  48. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/rocprof_sdk.py +0 -0
  49. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/rocprof_systems.py +0 -0
  50. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/skills/wafer-guide/SKILL.md +0 -0
  51. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/specs_cli.py +0 -0
  52. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/ssh_keys.py +0 -0
  53. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/target_lock.py +0 -0
  54. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/targets.py +0 -0
  55. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/targets_cli.py +0 -0
  56. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/targets_ops.py +0 -0
  57. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/templates/__init__.py +0 -0
  58. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/templates/aiter_optimize.py +0 -0
  59. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/templates/ask_docs.py +0 -0
  60. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/templates/optimize_kernel.py +0 -0
  61. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/templates/optimize_kernelbench.py +0 -0
  62. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/templates/optimize_vllm.py +0 -0
  63. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/templates/trace_analyze.py +0 -0
  64. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/tests/test_eval_cli_parity.py +0 -0
  65. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/trace_compare.py +0 -0
  66. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/tracelens.py +0 -0
  67. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer/workspaces.py +0 -0
  68. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer_cli.egg-info/SOURCES.txt +0 -0
  69. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer_cli.egg-info/dependency_links.txt +0 -0
  70. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer_cli.egg-info/entry_points.txt +0 -0
  71. {wafer_cli-0.2.37 → wafer_cli-0.2.39}/wafer_cli.egg-info/requires.txt +0 -0
  72. {wafer_cli-0.2.37 → 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.37
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.37"
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
+ ]
@@ -1497,6 +1497,7 @@ def _make_agent_alias(name: str, doc: str) -> None:
1497
1497
  template_args: list[str] | None = typer.Option(None, "--args"),
1498
1498
  corpus: str | None = typer.Option(None, "--corpus"),
1499
1499
  no_sandbox: bool = typer.Option(False, "--no-sandbox"),
1500
+ no_proxy: bool = typer.Option(False, "--no-proxy"),
1500
1501
  ) -> None:
1501
1502
  agent(
1502
1503
  prompt=prompt,
@@ -1517,6 +1518,7 @@ def _make_agent_alias(name: str, doc: str) -> None:
1517
1518
  template_args=template_args,
1518
1519
  corpus=corpus,
1519
1520
  no_sandbox=no_sandbox,
1521
+ no_proxy=no_proxy,
1520
1522
  )
1521
1523
 
1522
1524
  alias_cmd.__doc__ = doc
@@ -1860,6 +1862,12 @@ def kernelbench_evaluate( # noqa: PLR0913, PLR0915
1860
1862
  help="Sync files and generate eval script but don't run. "
1861
1863
  "Prints the command to run manually (useful for wrapping with rocprof, etc.)",
1862
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
+ ),
1863
1871
  json_output: bool = typer.Option(
1864
1872
  False, "--json", help="Output as single JSON object (machine-readable)"
1865
1873
  ),
@@ -1951,14 +1959,24 @@ def kernelbench_evaluate( # noqa: PLR0913, PLR0915
1951
1959
  collector.finalize()
1952
1960
  raise typer.Exit(1) from None
1953
1961
 
1954
- collector.emit("pool_acquire", pool=pool, count=len(usable_targets))
1955
- 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)
1956
1965
  acquired_target = pool_lock_context.__enter__()
1957
1966
 
1958
1967
  if acquired_target is None:
1959
1968
  # Exit context manager before raising to avoid resource leak
1960
1969
  pool_lock_context.__exit__(None, None, None)
1961
- 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)
1962
1980
  collector.finalize()
1963
1981
  raise typer.Exit(1)
1964
1982
 
@@ -2313,6 +2331,12 @@ def gpumode_evaluate( # noqa: PLR0913, PLR0915
2313
2331
  True, "--sync-artifacts/--no-sync-artifacts", help="Download artifacts"
2314
2332
  ),
2315
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
+ ),
2316
2340
  ) -> None:
2317
2341
  """Run kernel evaluation in GPUMode format (functional).
2318
2342
 
@@ -2392,14 +2416,21 @@ def gpumode_evaluate( # noqa: PLR0913, PLR0915
2392
2416
  typer.echo(" Run 'wafer auth status' to see which providers need setup.", err=True)
2393
2417
  raise typer.Exit(1) from None
2394
2418
 
2419
+ effective_timeout = pool_timeout if pool_timeout > 0 else None
2395
2420
  typer.echo(f"Acquiring target from pool '{pool}' ({len(usable_targets)} targets)...")
2396
- pool_lock_context = acquire_from_pool(usable_targets)
2421
+ pool_lock_context = acquire_from_pool(usable_targets, timeout=effective_timeout)
2397
2422
  acquired_target = pool_lock_context.__enter__()
2398
2423
 
2399
2424
  if acquired_target is None:
2400
2425
  # Exit context manager before raising to avoid resource leak
2401
2426
  pool_lock_context.__exit__(None, None, None)
2402
- 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)
2403
2434
  typer.echo(f" Targets: {', '.join(usable_targets)}", err=True)
2404
2435
  raise typer.Exit(1)
2405
2436
 
@@ -7749,16 +7780,24 @@ def compare_analyze(
7749
7780
  "-f",
7750
7781
  help="Output format: text, text-layers, csv, csv-layers, json",
7751
7782
  ),
7752
- 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
+ ),
7753
7786
  phase: str = typer.Option(
7754
7787
  "all",
7755
7788
  "--phase",
7756
7789
  help="Filter by phase: all, prefill, decode",
7757
7790
  ),
7758
7791
  layers: bool = typer.Option(False, "--layers", help="Show layer-wise performance breakdown"),
7759
- all: bool = typer.Option(False, "--all", help="Show all items (no truncation for layers, operations, kernels)"),
7760
- stack_traces: bool = typer.Option(False, "--stack-traces", help="Show Python stack traces for operations"),
7761
- 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
+ ),
7762
7801
  ) -> None:
7763
7802
  """Compare GPU traces from two platforms platforms.
7764
7803
 
@@ -7822,13 +7861,17 @@ def compare_fusion_cmd(
7822
7861
  "-f",
7823
7862
  help="Output format: text, csv, json",
7824
7863
  ),
7825
- 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
+ ),
7826
7867
  min_group_size: int = typer.Option(
7827
7868
  50,
7828
7869
  "--min-group-size",
7829
7870
  help="Minimum correlation group size to analyze",
7830
7871
  ),
7831
- 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
+ ),
7832
7875
  ) -> None:
7833
7876
  """Analyze kernel fusion differences between AMD and NVIDIA traces.
7834
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.37
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