resolveCommands = (loadedPlugin, config, commandPrefix = '') => {
    if (!config.commands) return
    for (const [commandName, commandConfig] of Object.entries(
      config.commands,
    )) {
      if (commandConfig.type === 'entrypoint') continue
      const fullCommandName = `${commandPrefix}${commandName}`
      if (commandConfig.type !== 'container') {
        const schema = commands.has(fullCommandName)
          ? _.merge({}, commands.get(fullCommandName))
          : {
              usage: commandConfig.usage,
              serviceDependencyMode: 'required',
              isExtension: true,
              sourcePlugin: loadedPlugin,
              isHidden: commandConfig.isHidden,
              noSupportNotice: commandConfig.noSupportNotice,
              options: {},
            }
        if (commandConfig.lifecycleEvents)
          schema.lifecycleEvents = commandConfig.lifecycleEvents
        if (commandConfig.options) {
          for (const [optionName, optionConfig] of Object.entries(
            commandConfig.options,
          )) {
            if (!schema.options[optionName]) {
              schema.options[optionName] = optionConfig
              if (!optionConfig.type) {
                if (!missingOptionTypes.has(loadedPlugin)) {
                  missingOptionTypes.set(loadedPlugin, new Set())
                }
                missingOptionTypes.get(loadedPlugin).add(optionName)
              }
            }
          }
        }

        // Put common options to end of index
        for (const optionName of Object.keys(commonOptions))
          delete schema.options[optionName]
        Object.assign(schema.options, commonOptions)

        commands.set(fullCommandName, schema)
      }
      resolveCommands(loadedPlugin, commandConfig, `${fullCommandName} `)
    }
  }
Recursively processes a configuration object for a plugin, mapping out its
commands and their options. It skips commands of type 'entrypoint', and for
other commands, it creates or updates a schema with details like usage,
lifecycle events, and options. If an option is missing the 'type' property,
it is added to the `missingOptionTypes` set for later processing.

@param {Object} loadedPlugin - The loaded plugin object.
@param {Object} config - The configuration object for the plugin.
@param {string} commandPrefix - The prefix for the command (default is '').