* @brief Builds a "Unknown command" error response with did_you_mean suggestions. */
| 242 | * @brief Builds a "Unknown command" error response with did_you_mean suggestions. |
| 243 | */ |
| 244 | API::CommandResponse API::CommandRegistry::buildUnknownCommandResponse(const QString& name, |
| 245 | const QString& id) const |
| 246 | { |
| 247 | QVector<QPair<int, QString>> ranked; |
| 248 | ranked.reserve(m_commands.size()); |
| 249 | for (auto it = m_commands.cbegin(); it != m_commands.cend(); ++it) |
| 250 | ranked.append({similarityScore(name, it.key()), it.key()}); |
| 251 | |
| 252 | std::sort( |
| 253 | ranked.begin(), ranked.end(), [](const auto& a, const auto& b) { return a.first < b.first; }); |
| 254 | |
| 255 | QJsonArray suggestions; |
| 256 | const int kMax = std::min<int>(5, ranked.size()); |
| 257 | for (int i = 0; i < kMax; ++i) { |
| 258 | QJsonObject hint; |
| 259 | hint[QStringLiteral("name")] = ranked[i].second; |
| 260 | hint[QStringLiteral("description")] = m_commands[ranked[i].second].description; |
| 261 | suggestions.append(hint); |
| 262 | } |
| 263 | |
| 264 | QJsonObject data; |
| 265 | data[QStringLiteral("did_you_mean")] = suggestions; |
| 266 | data[QStringLiteral("hint")] = |
| 267 | QStringLiteral("Use meta.listCommands to browse the full surface, then meta.describeCommand " |
| 268 | "for the exact schema before invoking."); |
| 269 | |
| 270 | return CommandResponse::makeError( |
| 271 | id, ErrorCode::UnknownCommand, QStringLiteral("Unknown command: %1").arg(name), data); |
| 272 | } |
| 273 | |
| 274 | /** |
| 275 | * @brief Attaches inputSchema + structured category to a failed response. |