///|
async fn main {
  let args = @env.args()[1:]
  // `run` is synchronous, so stdin is read before it when the command needs
  // it.
  let stdin : Result[Bytes, Error] = if @cli.reads_stdin(args) {
    Ok(@stdio.stdin.read_all().binary()) catch {
      e => Err(e)
    }
  } else {
    Err(Failure("stdin was not read"))
  }
  let io : @cli.Io = {
    read_file_bytes: Some(path => {
      @fs.read_file_to_bytes(path) catch {
        IOError(message) => raise Failure(message)
      }
    }),
    read_stdin_bytes: Some(() => {
      match stdin {
        Ok(bytes) => bytes
        Err(e) => raise e
      }
    }),
    read_file: path => {
      @fs.read_file_to_string(path) catch {
        IOError(message) => raise Failure(message)
      }
    },
    write_file: (path, text) => {
      @fs.write_string_to_file(path, text) catch {
        IOError(message) => raise Failure(message)
      }
    },
    read_stdin: () => {
      match stdin {
        Ok(bytes) => @utf8.decode(bytes)
        Err(e) => raise e
      }
    },
    color_default: stderr_is_terminal() && @env.get_env_var("NO_COLOR") is None,
    // The only wall clock in the project: the library gets it injected.
    clock: Some({
      now: () => {
        let ms = @env.now().reinterpret_as_int64()
        @time.unix(ms / 1000L, nanosecond=(ms % 1000L).to_int() * 1000000)
      },
    }),
  }
  let outcome = @cli.run(args, io~)
  if outcome.stdout_bytes is Some(bytes) {
    @stdio.stdout.write(bytes)
  } else if outcome.stdout != "" {
    println(outcome.stdout.trim_end(chars="\n"))
  }
  if outcome.stderr != "" {
    eprintln(outcome.stderr.trim_end(chars="\n"))
  }
  if outcome.status != 0 {
    @sys.exit(outcome.status)
  }
}