cli: drop exceptions from KompanionApp
This commit is contained in:
parent
a84af5d464
commit
8479c23234
|
|
@ -133,13 +133,17 @@ void writeDsnToConfig(const std::string& dsn) {
|
|||
#endif
|
||||
}
|
||||
|
||||
std::string readFileUtf8(const QString& path) {
|
||||
bool readFileUtf8(const QString& path, std::string& out, QString* error) {
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
throw std::runtime_error(QString("Unable to open request file: %1").arg(path).toStdString());
|
||||
if (error) {
|
||||
*error = QStringLiteral("Unable to open request file: %1").arg(path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const QByteArray data = file.readAll();
|
||||
return QString::fromUtf8(data).toStdString();
|
||||
out = QString::fromUtf8(data).toStdString();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool looksLikeFile(const QString& value) {
|
||||
|
|
@ -307,13 +311,20 @@ bool testConnection(const std::string& dsn, QString* error = nullptr) {
|
|||
return opened;
|
||||
}
|
||||
|
||||
bool schemaExists(QSqlDatabase& db) {
|
||||
bool schemaExists(QSqlDatabase& db, bool* exists, QString* error) {
|
||||
QSqlQuery query(db);
|
||||
if (!query.exec(QStringLiteral("SELECT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname='public' AND tablename='memory_items')"))) {
|
||||
throw std::runtime_error(query.lastError().text().toStdString());
|
||||
if (error) {
|
||||
*error = query.lastError().text();
|
||||
}
|
||||
if (!query.next()) return false;
|
||||
return query.value(0).toBool();
|
||||
return false;
|
||||
}
|
||||
if (!query.next()) {
|
||||
if (exists) *exists = false;
|
||||
return true;
|
||||
}
|
||||
if (exists) *exists = query.value(0).toBool();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool applySchemaFiles(QSqlDatabase& db,
|
||||
|
|
@ -380,29 +391,48 @@ bool ensureSchema(const std::string& dsn,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
try {
|
||||
if (schemaExists(db)) {
|
||||
bool exists = false;
|
||||
QString err;
|
||||
if (!schemaExists(db, &exists, &err)) {
|
||||
out << "Failed to check schema: " << err << "\n";
|
||||
db.close();
|
||||
db = QSqlDatabase();
|
||||
QSqlDatabase::removeDatabase(connName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
if (verbose) out << "Schema already present.\n";
|
||||
success = true;
|
||||
db.close();
|
||||
db = QSqlDatabase();
|
||||
QSqlDatabase::removeDatabase(connName);
|
||||
return true;
|
||||
}
|
||||
if (!success) {
|
||||
|
||||
out << "Schema not found; applying migrations...\n";
|
||||
if (applySchemaFiles(db, out, verbose) && schemaExists(db)) {
|
||||
out << "Schema initialized successfully.\n";
|
||||
success = true;
|
||||
} else {
|
||||
if (!applySchemaFiles(db, out, verbose)) {
|
||||
out << "Schema application reported errors.\n";
|
||||
db.close();
|
||||
db = QSqlDatabase();
|
||||
QSqlDatabase::removeDatabase(connName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!schemaExists(db, &exists, &err) || !exists) {
|
||||
out << "Schema still missing after applying migrations.\n";
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
out << "Failed to ensure schema: " << ex.what() << "\n";
|
||||
if (!err.isEmpty()) {
|
||||
out << "Last error: " << err << "\n";
|
||||
}
|
||||
db.close();
|
||||
db = QSqlDatabase();
|
||||
QSqlDatabase::removeDatabase(connName);
|
||||
return success;
|
||||
return false;
|
||||
}
|
||||
db.close();
|
||||
db = QSqlDatabase();
|
||||
QSqlDatabase::removeDatabase(connName);
|
||||
out << "Schema initialized successfully.\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<std::string> autoDetectDsn() {
|
||||
|
|
@ -578,50 +608,54 @@ int runInteractiveSession(KomMcpServer& server,
|
|||
out.flush();
|
||||
}
|
||||
|
||||
try {
|
||||
const std::string response = server.dispatch(toolName, payload);
|
||||
if (verbose) {
|
||||
out << "[response] " << QString::fromStdString(response) << "\n";
|
||||
} else {
|
||||
out << QString::fromStdString(response) << "\n";
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
out << "Error: " << ex.what() << "\n";
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
std::string resolveRequestPayload(const QCommandLineParser& parser,
|
||||
bool resolveRequestPayload(const QCommandLineParser& parser,
|
||||
const QStringList& positional,
|
||||
const QCommandLineOption& requestOption,
|
||||
const QCommandLineOption& stdinOption) {
|
||||
const QCommandLineOption& stdinOption,
|
||||
std::string& payloadOut,
|
||||
QString* error) {
|
||||
if (parser.isSet(stdinOption)) {
|
||||
return readAll(std::cin);
|
||||
payloadOut = readAll(std::cin);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (parser.isSet(requestOption)) {
|
||||
const QString arg = parser.value(requestOption);
|
||||
if (arg == "-" || parser.isSet(stdinOption)) {
|
||||
return readAll(std::cin);
|
||||
payloadOut = readAll(std::cin);
|
||||
return true;
|
||||
}
|
||||
if (looksLikeFile(arg)) {
|
||||
return readFileUtf8(arg);
|
||||
return readFileUtf8(arg, payloadOut, error);
|
||||
}
|
||||
return arg.toStdString();
|
||||
payloadOut = arg.toStdString();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (positional.size() > 1) {
|
||||
const QString arg = positional.at(1);
|
||||
if (arg == "-") {
|
||||
return readAll(std::cin);
|
||||
payloadOut = readAll(std::cin);
|
||||
return true;
|
||||
}
|
||||
if (looksLikeFile(arg)) {
|
||||
return readFileUtf8(arg);
|
||||
return readFileUtf8(arg, payloadOut, error);
|
||||
}
|
||||
return arg.toStdString();
|
||||
payloadOut = arg.toStdString();
|
||||
return true;
|
||||
}
|
||||
|
||||
return "{}";
|
||||
payloadOut = "{}";
|
||||
return true;
|
||||
}
|
||||
|
||||
void printToolList(const KomMcpServer& server) {
|
||||
|
|
@ -749,14 +783,20 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
|
||||
std::string request;
|
||||
try {
|
||||
request = resolveRequestPayload(parser, positional, requestOption, stdinOption);
|
||||
} catch (const std::exception& ex) {
|
||||
std::cerr << "Error: " << ex.what() << "\n";
|
||||
QString requestError;
|
||||
if (!resolveRequestPayload(parser,
|
||||
positional,
|
||||
requestOption,
|
||||
stdinOption,
|
||||
request,
|
||||
&requestError)) {
|
||||
const QString message = requestError.isEmpty()
|
||||
? QStringLiteral("Failed to resolve request payload.")
|
||||
: requestError;
|
||||
std::cerr << "Error: " << message.toStdString() << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
try {
|
||||
if (verbose) {
|
||||
std::cerr << "[request] " << request << "\n";
|
||||
}
|
||||
|
|
@ -766,8 +806,4 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
std::cout << response << std::endl;
|
||||
return 0;
|
||||
} catch (const std::exception& ex) {
|
||||
std::cerr << "Error: " << ex.what() << "\n";
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,15 @@ inline std::string runCommandCapture(const char* cmd, std::size_t maxBytes = 819
|
|||
(void)maxBytes;
|
||||
return "git status capture not supported on this platform";
|
||||
#else
|
||||
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
|
||||
struct PipeCloser {
|
||||
void operator()(FILE* file) const noexcept {
|
||||
if (file != nullptr) {
|
||||
pclose(file);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<FILE, PipeCloser> pipe(popen(cmd, "r"), PipeCloser{});
|
||||
if (!pipe) {
|
||||
return "git status unavailable";
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue