// SPDX-License-Identifier: LGPL-3.0-only // SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® // crafter-debug, the client agents drive an app with. Run is the whole // program but for the transport: main hands it a Connector that reaches an // instance over QUIC, and tests hand it one that reaches a Session in the // same process. // // Exit codes: // 0 done // 2 a usage error, or no debug build yet (the launcher's stub) // 3 no instance to talk to // 4 the app and this client speak different protocols // 5 timed out // 6 the app answered with an error // 1 is left to the launcher and `flatpak run` failing. export module Crafter.Debug.Cli:Client; import std; import Crafter.Debug.Core; export namespace Crafter::Debug::Cli { inline constexpr std::int32_t exitOk = 0; inline constexpr std::int32_t exitUsage = 2; inline constexpr std::int32_t exitNoInstance = 3; inline constexpr std::int32_t exitVersion = 4; inline constexpr std::int32_t exitTimeout = 5; inline constexpr std::int32_t exitError = 6; struct CallError { enum class Kind : std::uint8_t { // No connection: the app is gone, or its port does not answer. Unreachable, // Connected, but no reply within the timeout. TimedOut, // The reply was not what the protocol says. Broken, }; Kind kind = Kind::Unreachable; std::string message; }; // One request to an instance. The reply is the last object it sends; // objects before it are stream lines (`log --follow`), handed to // `onLine`, which returns false to stop. class Connection { public: virtual ~Connection() = default; virtual std::expected Call(const Value& request, std::chrono::milliseconds timeout, const std::function& onLine) = 0; }; using Connector = std::function(const InstanceRecord& instance)>; struct Environment { Connector connect; std::function()> list = ListInstances; std::ostream* out = &std::cout; std::ostream* err = &std::cerr; // Where a screenshot without -o goes, relative paths included. std::filesystem::path cwd = std::filesystem::current_path(); // The project the launcher that started this client was written for // (CRAFTER_DEBUG_PROJECT). Its apps, the ones whose executable lies // under it, are picked without -i when other apps run too, and no // other app is. Empty: whichever app runs, as long as only one does. std::filesystem::path project; // Where lldb is here, for the attach command `debugger` prints: its // absolute path, since `flatpak enter` runs a command without the // sandbox's PATH, which /app/bin is on. Empty for none: gdb then. std::function lldb; }; std::int32_t Run(std::span args, Environment& environment); // The full reference an agent reads with `crafter-debug guide`. std::string_view Guide(); // "30s", "500ms", "2m", "1h"; a bare number is seconds. std::optional ParseDuration(std::string_view text); }