import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.spi.ToolProvider;

record Tool(String name, ToolProvider descriptor) {

  public static void main(String... args) {
    var finder =
        Finder.of(
            Tool.of(new Banner()),
            Tool.of(new Chain()),
            Tool.of("jar"),
            Tool.of("javac"),
            Tool.of("javadoc"),
            Tool.of("jlink"));

    finder.findAll().stream().sorted(Comparator.comparing(Tool::name)).forEach(System.out::println);

    if (args.length == 0) {
      finder.run("banner", "a", "b", "c");
      finder.run("javac", "--version");
      return;
    }

    finder.run(args[0], Arrays.copyOfRange(args, 1, args.length));
  }

  static Tool of(String name) {
    return Tool.of(ToolProvider.findFirst(name).orElseThrow());
  }

  static Tool of(ToolProvider provider) {
    return new Tool(provider.name(), provider);
  }

  interface Runner {
    int run(String name, String... args);
  }

  interface Finder extends Runner {

    List<Tool> findAll();

    default Optional<Tool> find(String name) {
      return findAll().stream().filter(tool -> tool.name().equals(name)).findFirst();
    }

    default int run(String name, String... args) {
      var provider = find(name).orElseThrow(() -> new NoSuchElementException(name)).descriptor();
      return provider instanceof Operator operator
          ? operator.run(this, args)
          : provider.run(OUT, ERR, args);
    }

    static Finder of(Tool... tools) {
      record DirectToolFinder(List<Tool> findAll) implements Finder {}
      return new DirectToolFinder(List.of(tools));
    }

    PrintWriter OUT = new PrintWriter(System.out, true);
    PrintWriter ERR = new PrintWriter(System.err, true);
  }

  record Banner(String name) implements ToolProvider {
    Banner() {
      this("banner");
    }

    public int run(PrintWriter out, PrintWriter err, String... args) {
      var text = args.length == 0 ? "Usage: banner TEXT..." : String.join(" ", args).toUpperCase();
      var dash = "=".repeat(text.length());
      out.printf("""
          %s
          %s
          %s
          """, dash, text, dash);
      return 0;
    }
  }

  interface Operator extends ToolProvider {
    default int run(PrintWriter out, PrintWriter err, String... args) {
      throw new UnsupportedOperationException();
    }

    int run(Runner runner, String... args);
  }

  record Chain(String name) implements Operator {
    Chain() {
      this("chain");
    }

    public int run(Runner runner, String... args) {
      for (var name : args) {
        var code = runner.run(name);
        if (code != 0) return code;
      }
      return 0;
    }
  }
}

@@ -331,18 +331,23 @@
  Finder.
-of
+compose
 (%0A      
@@ -344,32 +344,42 @@
 se(%0A            
+Finder.of(
 Tool.of(new Bann
@@ -380,36 +380,24 @@
 w Banner()),
-%0A           
  Tool.of(new
@@ -405,16 +405,17 @@
 Chain())
+)
 ,%0A      
@@ -412,32 +412,42 @@
 )),%0A            
+Finder.of(
 Tool.of(%22jar%22),%0A
@@ -445,28 +445,16 @@
 (%22jar%22),
-%0A           
  Tool.of
@@ -459,36 +459,24 @@
 of(%22javac%22),
-%0A           
  Tool.of(%22ja
@@ -483,28 +483,16 @@
 vadoc%22),
-%0A           
  Tool.of
@@ -501,16 +501,17 @@
 jlink%22))
+)
 ;%0A%0A    f
@@ -1561,24 +1561,582 @@
 gs);%0A    %7D%0A%0A
+    static Finder compose(Finder... finders) %7B%0A      record CompositeFinder(List%3CFinder%3E finders) implements Finder %7B%0A        public List%3CTool%3E findAll() %7B%0A          return finders.stream().flatMap(finder -%3E finder.findAll().stream()).toList();%0A        %7D%0A%0A        public Optional%3CTool%3E find(String name) %7B%0A          for (var finder : finders) %7B%0A            var tool = finder.find(name);%0A            if (tool.isPresent()) return tool;%0A          %7D%0A          return Optional.empty();%0A        %7D%0A      %7D%0A      return new CompositeFinder(List.of(finders));%0A    %7D%0A%0A
     static F

Add support for composing finders