Code review comment: The one option we have is to auto accept them, or do like you did  here and stop the algorithm by asking to select/confirm the extension explicitly. I was fine with option 1 but I can be convinced otherwise. If we go with option 2, we need a clearer text to describe what is going on as the general non matching text is confusing.

Code before review:
public AddExtensionResult addExtensions(final Set<String> extensions) throws IOException {
if (extensions == null || extensions.isEmpty()) {
return new AddExtensionResult(false, true);
}
boolean updated = false;
boolean success = true;
List<Dependency> dependenciesFromBom = getDependenciesFromBom();
for (String query : extensions) {
List<Extension> registry = MojoUtils.loadExtensions();
SelectionResult result = select(query, registry);
if (!result.matches()) {
StringBuilder sb = new StringBuilder();
Set<Extension> candidates = result.getExtensions();
if (candidates.isEmpty() && query.contains(":")) {
updated = addExtensionAsGAV(query) || updated;
} else if (candidates.isEmpty()) {
print(NOK + " Cannot find a dependency matching '" + query + "', maybe a typo?");
success = false;
} else if (candidates.size() == 1) {
sb.append(NOK).append(" One extension matching '").append(query).append("'");
sb.append(System.lineSeparator()).append("     * ").append(candidates.iterator().next().managementKey());
sb.append(System.lineSeparator()).append("     Use the exact name or the full GAV to add the extension");
print(sb.toString());
success = false;
} else {
sb.append(NOK).append(" Multiple extensions matching '").append(query).append("'");
result.getExtensions()
.forEach(extension -> sb.append(System.lineSeparator()).append("     * ")
.append(extension.managementKey()));
sb.append(System.lineSeparator()).append("     Be more specific e.g using the exact name or the full GAV.");
print(sb.toString());
success = false;
}
} else {
final Extension extension = result.getMatch();
updated = addDependency(dependenciesFromBom, extension) || updated;
}
}
if (updated) {
ByteArrayOutputStream pomOutputStream = new ByteArrayOutputStream();
MojoUtils.write(model, pomOutputStream);
writer.write(pom, pomOutputStream.toString("UTF-8"));
}
return new AddExtensionResult(updated, success);
}

Line under review: sb.append(NOK).append(" One extension matching '").append(query).append("'");

Code after addressing the review:
public AddExtensionResult addExtensions(final Set<String> extensions) throws IOException {
if (extensions == null || extensions.isEmpty()) {
return new AddExtensionResult(false, true);
}
boolean updated = false;
boolean success = true;
List<Dependency> dependenciesFromBom = getDependenciesFromBom();
List<Extension> registry = MojoUtils.loadExtensions();
for (String query : extensions) {
if (query.contains(":")) {
updated = addExtensionAsGAV(query) || updated;
} else {
SelectionResult result = select(query, registry, false);
if (!result.matches()) {
StringBuilder sb = new StringBuilder();
Set<Extension> candidates = result.getExtensions();
if (candidates.isEmpty()) {
print(NOK + " Cannot find a dependency matching '" + query + "', maybe a typo?");
success = false;
} else {
sb.append(NOK).append(" Multiple extensions matching '").append(query).append("'");
result.getExtensions()
.forEach(extension -> sb.append(System.lineSeparator()).append("     * ")
.append(extension.managementKey()));
sb.append(System.lineSeparator())
.append("     Be more specific e.g using the exact name or the full GAV.");
print(sb.toString());
success = false;
}
} else {
final Extension extension = result.getMatch();
updated = addDependency(dependenciesFromBom, extension) || updated;
}
}
}
if (updated) {
ByteArrayOutputStream pomOutputStream = new ByteArrayOutputStream();
MojoUtils.write(model, pomOutputStream);
writer.write(pom, pomOutputStream.toString("UTF-8"));
}
return new AddExtensionResult(updated, success);
}