diff --git a/features/steps/tdd_validation_attach_named_options_steps.py b/features/steps/tdd_validation_attach_named_options_steps.py index 0a56c112f..940269b15 100644 --- a/features/steps/tdd_validation_attach_named_options_steps.py +++ b/features/steps/tdd_validation_attach_named_options_steps.py @@ -115,15 +115,19 @@ def step_named_opts_attach_succeeds(context: Context) -> None: def step_named_opts_received_coverage_threshold( context: Context, expected_val: str ) -> None: - """Verify the service received coverage-threshold in the args dict.""" + """Verify the service received coverage_threshold in the args dict. + + The CLI converts hyphens in option names to underscores when forwarding + to the service layer (``--coverage-threshold`` → ``coverage_threshold``). + """ call_kwargs = context.named_opts_mock_service.attach_validation.call_args assert call_kwargs is not None, "attach_validation was not called" args_dict = call_kwargs.kwargs.get("args") or {} - assert "coverage-threshold" in args_dict, ( - f"Expected 'coverage-threshold' in args, got: {args_dict}" + assert "coverage_threshold" in args_dict, ( + f"Expected 'coverage_threshold' in args, got: {args_dict}" ) - assert args_dict["coverage-threshold"] == expected_val, ( - f"Expected coverage-threshold={expected_val!r}, got {args_dict['coverage-threshold']!r}" + assert args_dict["coverage_threshold"] == expected_val, ( + f"Expected coverage_threshold={expected_val!r}, got {args_dict['coverage_threshold']!r}" ) diff --git a/robot/helper_validation_attach_named_options.py b/robot/helper_validation_attach_named_options.py index 5c7159467..ea322b792 100644 --- a/robot/helper_validation_attach_named_options.py +++ b/robot/helper_validation_attach_named_options.py @@ -82,8 +82,8 @@ def attach_with_coverage_threshold() -> None: sys.exit(1) args_dict = call_kwargs.kwargs.get("args") or {} - if args_dict.get("coverage-threshold") != "90": - print(f"FAIL: expected args={{'coverage-threshold': '90'}}, got {args_dict!r}") + if args_dict.get("coverage_threshold") != "90": + print(f"FAIL: expected args={{'coverage_threshold': '90'}}, got {args_dict!r}") sys.exit(1) print("validation-attach-named-option-coverage-threshold-ok") diff --git a/src/cleveragents/cli/commands/validation.py b/src/cleveragents/cli/commands/validation.py index 5a4c0b47a..8fea9a511 100644 --- a/src/cleveragents/cli/commands/validation.py +++ b/src/cleveragents/cli/commands/validation.py @@ -291,18 +291,19 @@ def attach( ) -> None: """Attach a validation to a resource. - Extra validation arguments are passed as named options using ``--key value`` - format (e.g. ``--coverage-threshold 90``). The ``--`` prefix is stripped - and the remaining key/value pairs are forwarded to the validation service. - The validation mode (required or informational) is determined by the validation's registered definition, not overridden at attach time. + Validation-specific arguments are passed as named options using the + ``--key value`` format (e.g. ``--coverage-threshold 90``). Hyphens in + option names are converted to underscores in the stored argument dict + (e.g. ``--coverage-threshold`` becomes ``coverage_threshold``). + Examples: agents validation attach git-checkout/my-repo local/coverage-check agents validation attach --project myproj git-checkout/my-repo local/lint - agents validation attach git-checkout/my-repo local/coverage-check \ - --coverage-threshold 90 + agents validation attach --project local/api-service \\ + local/api-repo local/run-tests --coverage-threshold 90 """ try: # Parse extra named options from ctx.args (--key value pairs). @@ -315,15 +316,20 @@ def attach( while i < len(raw_extra): token = raw_extra[i] if token.startswith("--"): - key = token[2:] # strip leading "--" + key = token[2:].replace( + "-", "_" + ) # --coverage-threshold → coverage_threshold if not key: console.print( "[red]Invalid option:[/red] bare '--' is not allowed" ) raise typer.Abort() - # Next token is the value - if i + 1 >= len(raw_extra): - console.print(f"[red]Missing value for option:[/red] {token}") + # Next token is the value (must not be another --flag) + if i + 1 >= len(raw_extra) or raw_extra[i + 1].startswith("--"): + console.print( + f"[red]Missing value for option:[/red] {token} " + "(expected --key value, e.g. --coverage-threshold 90)" + ) raise typer.Abort() val = raw_extra[i + 1] extra_args[key] = val