diff --git a/myagents/commands/provider.py b/myagents/commands/provider.py index 25b8bc0..e426dc7 100644 --- a/myagents/commands/provider.py +++ b/myagents/commands/provider.py @@ -100,7 +100,7 @@ def _do_switch( ) -@click.group("provider", invoke_without_command=True) +@click.group("provider", invoke_without_command=True, cls=_ProviderGroup) @click.option("--key", help="API key (scripting only; appears in shell history)") @click.option("--model", help="Override the default model") @click.option("--base-url", help="Override the provider base URL") @@ -148,6 +148,40 @@ def provider_cmd( _do_switch(provider, key=key, model=model, base_url=base_url, yes=yes) +class _ProviderGroup(click.Group): + """A Group whose :attr:`invoke_without_command` also fires when the first + positional arg is a non-subcommand value (like a provider ID). + + Click 8.4.2 ``resolve_command`` raises ``NoSuchCommand`` before + ``invoke_without_command`` can be consulted; we short-circuit that here. + """ + + def invoke(self, ctx: click.Context): + # No positional args → bare group invocation (list). + if not ctx._protected_args: + if self.invoke_without_command: + with ctx: + return click.MultiCommand.invoke(self, ctx) + ctx.fail("Missing command.") + + cmd_name = ctx._protected_args[0] + cmd = self.get_command(ctx, cmd_name) + + if cmd is not None: + # Known subcommand ("list", "current", "key") — normal dispatch. + return click.Group.invoke(self, ctx) + + if self.invoke_without_command: + # Not a subcommand — route positional args into ctx.args and + # invoke the group callback directly (skip resolve_command). + ctx.args = [*ctx._protected_args, *ctx.args] + ctx._protected_args.clear() + with ctx: + return click.MultiCommand.invoke(self, ctx) + + ctx.fail(f"No such command '{cmd_name}'.") + + @provider_cmd.command("list") def provider_list() -> None: """List available providers."""