Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/brigade/cli/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ def _terminalize_escaped_run(
raise


def _non_empty_task(value: str) -> str:
if not value.strip():
raise argparse.ArgumentTypeError("must not be empty or whitespace")
return value


def _non_negative_seconds(value: str) -> float:
try:
parsed = float(value)
Expand All @@ -93,7 +99,11 @@ def _non_negative_seconds(value: str) -> float:
def register(sub: argparse._SubParsersAction) -> None:
# run
p_run = sub.add_parser("run", help="Run a bounded cross-model orchestration task.")
p_run.add_argument("task", help="Task for the aboyeur to plan, dispatch, and synthesize.")
p_run.add_argument(
"task",
type=_non_empty_task,
help="Task for the aboyeur to plan, dispatch, and synthesize.",
)
p_run.add_argument(
"--roster",
type=Path,
Expand Down
41 changes: 41 additions & 0 deletions tests/test_run_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from brigade import cli
from brigade import localio
from brigade import proc
from brigade import roster
from brigade import runguard
from brigade import runs_cmd

Expand All @@ -35,6 +36,46 @@ def test_run_cli_rejects_missing_cwd(tmp_path, capsys):
assert "--cwd is not a directory" in capsys.readouterr().err


@pytest.mark.parametrize("task", ["", " \t\n"])
def test_run_cli_rejects_blank_task_before_run_setup(tmp_path, capsys, monkeypatch, task):
config_dir = tmp_path / ".brigade"
config_dir.mkdir()
(config_dir / "roster.toml").write_text('orchestrator = "chef"\n\n[agents.chef]\ncli = "codex"\nrole = "plan"\n')
runs_dir = config_dir / "runs"
calls = []
resolve_roster = roster.resolve_roster

def tracked_resolve_roster(*args, **kwargs):
calls.append("resolve_roster")
return resolve_roster(*args, **kwargs)

def tracked_make_run_dir(*args, **kwargs):
calls.append("make_run_dir")
return runs_dir / "unexpected"

@contextmanager
def tracked_run_lock(*args, **kwargs):
calls.append("run_lock")
yield

def tracked_run(*args, **kwargs):
calls.append("run")
return 0

monkeypatch.setattr(roster, "resolve_roster", tracked_resolve_roster)
monkeypatch.setattr(aboyeur, "make_run_dir", tracked_make_run_dir)
monkeypatch.setattr(runguard, "run_lock", tracked_run_lock)
monkeypatch.setattr(aboyeur, "run", tracked_run)

with pytest.raises(SystemExit) as exc:
cli.main(["run", task, "--cwd", str(tmp_path)])

assert exc.value.code == 2
assert "argument task: must not be empty or whitespace" in capsys.readouterr().err
assert calls == []
assert not runs_dir.exists()


def test_run_cli_loads_roster_and_dispatches(tmp_path, monkeypatch):
roster_path = tmp_path / "roster.toml"
roster_path.write_text(
Expand Down