Skip to content

Activators

Activators control whether options or entire commands are available. Deactivated options are hidden from tab completion and help, and deactivated commands are invisible to the user.

Deactivation applies to all completion paths: interactive tab completion, dynamic --aesh-complete callbacks, and static shell completion scripts (static scripts honor activators since 3.18). For options that should still parse when typed but never be suggested, use OptionVisibility.HIDDEN instead of an activator.

OptionActivator

Enable or disable an option based on conditions. The ParsedCommand gives you access to the current command and the values of other options that have been parsed so far:

public interface OptionActivator {
    boolean isActivated(ParsedCommand parsedCommand);
}

Example: Conditional Options

SSL-related options should only appear when --secure is used:

import org.aesh.command.activator.OptionActivator;
import org.aesh.command.impl.internal.ParsedCommand;

public class SslOptionActivator implements OptionActivator {

    @Override
    public boolean isActivated(ParsedCommand parsedCommand) {
        // SSL options only active if --secure has been specified
        return parsedCommand.findLongOptionNoActivatorCheck("secure")
                .getValue() != null;
    }
}

Usage:

@CommandDefinition(name = "server", description = "Start the server")
public class ServerCommand implements Command<CommandInvocation> {

    @Option(name = "secure", hasValue = false, description = "Enable secure mode")
    private boolean secureMode = false;

    @Option(
        name = "cert",
        activator = SslOptionActivator.class,
        description = "SSL certificate (only in secure mode)"
    )
    private String certPath;

    @Option(
        name = "key",
        activator = SslOptionActivator.class,
        description = "SSL private key (only in secure mode)"
    )
    private String keyPath;

    @Override
    public CommandResult execute(CommandInvocation invocation) {
        if (secureMode) {
            invocation.println("Starting HTTPS with cert=" + certPath);
        } else {
            invocation.println("Starting HTTP server");
        }
        return CommandResult.SUCCESS;
    }
}

When --secure is not set, --cert and --key are hidden from tab completion and --help output.

CommandActivator

Control whether an entire command is visible and available:

public interface CommandActivator {
    boolean isActivated(ParsedCommand command);
}

Example: Admin-Only Commands

import org.aesh.command.activator.CommandActivator;
import org.aesh.command.impl.internal.ParsedCommand;

public class AdminCommandActivator implements CommandActivator {

    @Override
    public boolean isActivated(ParsedCommand command) {
        return "admin".equals(System.getProperty("user.role", "user"));
    }
}
@CommandDefinition(
    name = "shutdown",
    description = "Shutdown the server",
    activator = AdminCommandActivator.class
)
public class ShutdownCommand implements Command<CommandInvocation> {

    @Override
    public CommandResult execute(CommandInvocation invocation) {
        invocation.println("Shutting down...");
        return CommandResult.SUCCESS;
    }
}

The shutdown command only appears in tab completion and help when user.role is admin. Users without admin role cannot discover or execute it.

Platform-Conditional Commands

A common use case is a cross-platform CLI where some commands only exist on one platform (e.g. a vm appliance command that is macOS-only because the managed runtime runs natively on Linux). Gate it with a CommandActivator behind a single command tree instead of maintaining one top-level command per platform:

import org.aesh.command.activator.CommandActivator;
import org.aesh.command.impl.internal.ParsedCommand;

public class MacOnly implements CommandActivator {

    @Override
    public boolean isActivated(ParsedCommand command) {
        return Platform.isMacOS();
    }
}
@CommandDefinition(
    name = "vm",
    description = "Manage the VM appliance (macOS only)",
    activator = MacOnly.class,
    groupCommands = { VmStartCommand.class, VmStopCommand.class }
)
public class VmCommand implements Command<CommandInvocation> { }

On Linux, isx vm is rejected at execution time and never appears in --help, tab completion, or generated shell completion scripts — no post-filtering of the scripts required.

An activator hides the command at runtime, but the class still ships in the binary. If the code must be absent from a native-image build entirely (GraalVM dead-code elimination via build-time-folded constants), register a separate top-level command per platform instead, and use a CompletionFilter to keep generated completions in step.

Conditional Required Options

Combine activators with required = true to make options conditionally required:

public class OutputFileActivator implements OptionActivator {

    @Override
    public boolean isActivated(ParsedCommand parsedCommand) {
        // Output file only required when not in verbose mode
        return parsedCommand.findLongOptionNoActivatorCheck("verbose")
                .getValue() == null;
    }
}

@CommandDefinition(name = "process", description = "Process data")
public class ProcessCommand implements Command<CommandInvocation> {

    @Option(name = "verbose", hasValue = false, description = "Verbose output to console")
    private boolean verbose = false;

    @Option(
        name = "output",
        activator = OutputFileActivator.class,
        required = true,
        description = "Output file (required unless --verbose)"
    )
    private String outputFile;

    @Override
    public CommandResult execute(CommandInvocation invocation) {
        if (verbose) {
            invocation.println("Processing... (verbose output)");
        } else {
            invocation.println("Writing output to " + outputFile);
        }
        return CommandResult.SUCCESS;
    }
}

When --verbose is used, --output is deactivated and not required. Without --verbose, --output is required.