async run(commandsArray) {
    this.commandRunStartTime = Date.now()
    if (this.serverless.processedInput.commands[0] !== 'plugin') {
      // first initialize hooks
      for (const { hook } of this.hooks.initialize || []) await hook()
    }

    let deferredBackendNotificationRequest

    try {
      await this.invoke(commandsArray)
    } catch (commandException) {
      try {
        for (const { hook } of this.hooks.error || [])
          await hook(commandException)
      } catch (errorHookException) {
        const errorHookExceptionMeta = tokenizeException(errorHookException)
        log.warning(
          `The "error" hook crashed with:\n${
            errorHookExceptionMeta.stack || errorHookExceptionMeta.message
          }`,
        )
      } finally {
        await deferredBackendNotificationRequest
        throw commandException // eslint-disable-line no-unsafe-finally
      }
    }

    try {
      for (const { hook } of this.hooks.finalize || []) await hook()
    } catch (finalizeHookException) {
      await deferredBackendNotificationRequest
      throw finalizeHookException
    }
  }
Executes the provided commands array. This method initializes hooks, invokes
the commands, and handles any exceptions that occur during command execution.
If an exception occurs, it triggers the error hooks and rethrows the exception.
After successful execution or error handling, it triggers the finalize hooks.
If an exception occurs during finalize, it rethrows the exception.

@async
@param {Array} commandsArray - The array of commands to execute.
@throws {Error} If there's an error in command execution or during the
execution of error or finalize hooks.