Refactor CLI Service Structure and Enhance AI Integration

- Restructured CLI service source files to improve organization, moving files into dedicated directories for better maintainability.
- Introduced new AI service components, including `AIService`, `MockAIService`, and `GeminiAIService`, to facilitate natural language command generation.
- Implemented `PolicyEvaluator` and `ProposalRegistry` for enhanced proposal management and policy enforcement in AI workflows.
- Updated CMake configurations to reflect new file paths and ensure proper linking of the restructured components.
- Enhanced test suite with new test workflow generation capabilities, improving the robustness of automated testing.

This commit significantly advances the architecture of the z3ed system, laying the groundwork for more sophisticated AI-driven features and streamlined development processes.
This commit is contained in:
scawful
2025-10-03 09:54:27 -04:00
parent b89dcca93f
commit 90ddc3d50c
45 changed files with 224 additions and 167 deletions

View File

@@ -0,0 +1,212 @@
#include "cli/service/rom/rom_sandbox_manager.h"
#include <algorithm>
#include <cstdlib>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/time/time.h"
#include "util/macro.h"
namespace yaze {
namespace cli {
namespace {
std::filesystem::path DetermineDefaultRoot() {
if (const char* env_root = std::getenv("YAZE_SANDBOX_ROOT")) {
return std::filesystem::path(env_root);
}
std::error_code ec;
auto temp_dir = std::filesystem::temp_directory_path(ec);
if (ec) {
// Fallback to current working directory if temp is unavailable.
return std::filesystem::current_path() / "yaze" / "sandboxes";
}
return temp_dir / "yaze" / "sandboxes";
}
std::filesystem::path ResolveUniqueDirectory(
const std::filesystem::path& root,
absl::string_view id) {
return root / std::string(id);
}
} // namespace
RomSandboxManager& RomSandboxManager::Instance() {
static RomSandboxManager* instance = new RomSandboxManager();
return *instance;
}
RomSandboxManager::RomSandboxManager()
: root_directory_(DetermineDefaultRoot()) {}
void RomSandboxManager::SetRootDirectory(const std::filesystem::path& root) {
std::lock_guard<std::mutex> lock(mutex_);
root_directory_ = root;
(void)EnsureRootExistsLocked();
}
const std::filesystem::path& RomSandboxManager::RootDirectory() const {
return root_directory_;
}
absl::Status RomSandboxManager::EnsureRootExistsLocked() {
std::error_code ec;
if (!std::filesystem::exists(root_directory_, ec)) {
if (!std::filesystem::create_directories(root_directory_, ec) && ec) {
return absl::InternalError(absl::StrCat(
"Failed to create sandbox root at ", root_directory_.string(),
": ", ec.message()));
}
}
return absl::OkStatus();
}
std::string RomSandboxManager::GenerateSandboxIdLocked() {
absl::Time now = absl::Now();
std::string time_component = absl::FormatTime("%Y%m%dT%H%M%S", now,
absl::LocalTimeZone());
++sequence_;
return absl::StrCat(time_component, "-", sequence_);
}
absl::StatusOr<RomSandboxManager::SandboxMetadata>
RomSandboxManager::CreateSandbox(Rom& rom, absl::string_view description) {
if (!rom.is_loaded()) {
return absl::FailedPreconditionError(
"Cannot create sandbox: ROM is not loaded");
}
std::filesystem::path source_path(rom.filename());
if (source_path.empty()) {
return absl::FailedPreconditionError(
"Cannot create sandbox: ROM filename is empty");
}
std::unique_lock<std::mutex> lock(mutex_);
RETURN_IF_ERROR(EnsureRootExistsLocked());
std::string id = GenerateSandboxIdLocked();
std::filesystem::path sandbox_dir =
ResolveUniqueDirectory(root_directory_, id);
lock.unlock();
std::error_code ec;
if (!std::filesystem::create_directories(sandbox_dir, ec) && ec) {
return absl::InternalError(absl::StrCat(
"Failed to create sandbox directory at ", sandbox_dir.string(),
": ", ec.message()));
}
std::filesystem::path sandbox_rom_path = sandbox_dir / source_path.filename();
Rom::SaveSettings settings;
settings.filename = sandbox_rom_path.string();
settings.save_new = false;
settings.backup = false;
settings.z3_save = true;
absl::Status save_status = rom.SaveToFile(settings);
if (!save_status.ok()) {
std::error_code cleanup_ec;
std::filesystem::remove_all(sandbox_dir, cleanup_ec);
return save_status;
}
lock.lock();
sandboxes_[id] = SandboxMetadata{
.id = id,
.directory = sandbox_dir,
.rom_path = sandbox_rom_path,
.source_rom = source_path.string(),
.description = std::string(description),
.created_at = absl::Now(),
};
active_sandbox_id_ = id;
return sandboxes_.at(id);
}
absl::StatusOr<RomSandboxManager::SandboxMetadata>
RomSandboxManager::ActiveSandbox() const {
std::lock_guard<std::mutex> lock(mutex_);
if (!active_sandbox_id_.has_value()) {
return absl::NotFoundError("No active sandbox");
}
auto it = sandboxes_.find(*active_sandbox_id_);
if (it == sandboxes_.end()) {
return absl::NotFoundError("Active sandbox metadata missing");
}
return it->second;
}
absl::StatusOr<std::filesystem::path>
RomSandboxManager::ActiveSandboxRomPath() const {
ASSIGN_OR_RETURN(auto meta, ActiveSandbox());
return meta.rom_path;
}
std::vector<RomSandboxManager::SandboxMetadata>
RomSandboxManager::ListSandboxes() const {
std::lock_guard<std::mutex> lock(mutex_);
std::vector<SandboxMetadata> list;
list.reserve(sandboxes_.size());
for (const auto& [_, metadata] : sandboxes_) {
list.push_back(metadata);
}
std::sort(list.begin(), list.end(),
[](const SandboxMetadata& a, const SandboxMetadata& b) {
return a.created_at < b.created_at;
});
return list;
}
absl::Status RomSandboxManager::RemoveSandbox(const std::string& id) {
std::lock_guard<std::mutex> lock(mutex_);
auto it = sandboxes_.find(id);
if (it == sandboxes_.end()) {
return absl::NotFoundError("Sandbox not found");
}
std::error_code ec;
std::filesystem::remove_all(it->second.directory, ec);
if (ec) {
return absl::InternalError(absl::StrCat(
"Failed to remove sandbox directory: ", ec.message()));
}
sandboxes_.erase(it);
if (active_sandbox_id_.has_value() && *active_sandbox_id_ == id) {
active_sandbox_id_.reset();
}
return absl::OkStatus();
}
absl::StatusOr<int> RomSandboxManager::CleanupOlderThan(absl::Duration max_age) {
std::vector<std::string> to_remove;
{
std::lock_guard<std::mutex> lock(mutex_);
absl::Time threshold = absl::Now() - max_age;
for (const auto& [id, metadata] : sandboxes_) {
if (metadata.created_at < threshold) {
to_remove.push_back(id);
}
}
}
int removed = 0;
for (const auto& id : to_remove) {
absl::Status status = RemoveSandbox(id);
if (!status.ok()) {
return status;
}
++removed;
}
return removed;
}
} // namespace cli
} // namespace yaze

View File

@@ -0,0 +1,92 @@
#ifndef YAZE_SRC_CLI_SERVICE_ROM_SANDBOX_MANAGER_H_
#define YAZE_SRC_CLI_SERVICE_ROM_SANDBOX_MANAGER_H_
#include <filesystem>
#include <mutex>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>
#include "absl/base/thread_annotations.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "app/rom.h"
namespace yaze {
namespace cli {
// RomSandboxManager coordinates creation and lifecycle management of sandboxed
// ROM copies. Agent workflows operate on sandboxes so that proposals can be
// reviewed before landing in the primary project ROM. The manager currently
// tracks sandboxes in-memory for the running process and persists files to a
// configurable root directory on disk.
class RomSandboxManager {
public:
struct SandboxMetadata {
std::string id;
std::filesystem::path directory;
std::filesystem::path rom_path;
std::string source_rom;
std::string description;
absl::Time created_at;
};
static RomSandboxManager& Instance();
// Set the root directory used for new sandboxes. Must be called before any
// sandboxes are created. If not set, a default rooted at the system temporary
// directory is used (or the value of the YAZE_SANDBOX_ROOT environment
// variable when present).
void SetRootDirectory(const std::filesystem::path& root);
const std::filesystem::path& RootDirectory() const;
// Creates a new sandbox by copying the provided ROM into a unique directory
// under the root. The new sandbox becomes the active sandbox for the current
// process. Metadata is returned describing the sandbox on success.
absl::StatusOr<SandboxMetadata> CreateSandbox(Rom& rom,
absl::string_view description);
// Returns the metadata for the active sandbox if one exists.
absl::StatusOr<SandboxMetadata> ActiveSandbox() const;
// Returns the absolute path to the active sandbox ROM copy. Equivalent to
// ActiveSandbox()->rom_path but with more descriptive errors when unset.
absl::StatusOr<std::filesystem::path> ActiveSandboxRomPath() const;
// List all sandboxes tracked during the current process lifetime. This will
// include the active sandbox (if any) and previously created sandboxes that
// have not been cleaned up.
std::vector<SandboxMetadata> ListSandboxes() const;
// Removes the sandbox identified by |id| from the index and deletes its on
// disk directory. If the sandbox is currently active the active sandbox is
// cleared. Missing sandboxes result in a NotFound status.
absl::Status RemoveSandbox(const std::string& id);
// Deletes any sandboxes that are older than |max_age|, returning the number
// of sandboxes removed. This is currently best-effort; individual removals
// may produce errors which are aggregated into the returned status.
absl::StatusOr<int> CleanupOlderThan(absl::Duration max_age);
private:
RomSandboxManager();
absl::Status EnsureRootExistsLocked();
std::string GenerateSandboxIdLocked();
std::filesystem::path root_directory_;
mutable std::mutex mutex_;
std::unordered_map<std::string, SandboxMetadata> sandboxes_;
std::optional<std::string> active_sandbox_id_;
int sequence_ ABSL_GUARDED_BY(mutex_) = 0;
};
} // namespace cli
} // namespace yaze
#endif // YAZE_SRC_CLI_SERVICE_ROM_SANDBOX_MANAGER_H_