imgui-frontend-engineer: refine agent editor wiring
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include "app/service/canvas_automation_service.h"
|
||||
#include "app/service/unified_grpc_server.h"
|
||||
#include "app/test/test_manager.h"
|
||||
#include "cli/service/agent/emulator_service_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
@@ -26,47 +27,8 @@ void Application::Initialize(const AppConfig& config) {
|
||||
config_ = config;
|
||||
LOG_INFO("App", "Initializing Application instance...");
|
||||
|
||||
#ifdef YAZE_WITH_GRPC
|
||||
// Initialize gRPC server if enabled
|
||||
if (config_.enable_test_harness) {
|
||||
LOG_INFO("App", "Initializing gRPC automation services...");
|
||||
canvas_automation_service_ = std::make_unique<CanvasAutomationServiceImpl>();
|
||||
grpc_server_ = std::make_unique<YazeGRPCServer>();
|
||||
|
||||
// Initialize server with all services
|
||||
// Note: RomService and ProposalApprovalManager will be connected later
|
||||
// when we have a session context, but we can start the server now.
|
||||
auto status = grpc_server_->Initialize(
|
||||
config_.test_harness_port,
|
||||
&yaze::test::TestManager::Get(),
|
||||
nullptr, // ROM not loaded yet
|
||||
nullptr, // Version manager not ready
|
||||
nullptr, // Approval manager not ready
|
||||
canvas_automation_service_.get()
|
||||
);
|
||||
|
||||
if (status.ok()) {
|
||||
status = grpc_server_->StartAsync(); // Start in background thread
|
||||
if (!status.ok()) {
|
||||
LOG_ERROR("App", "Failed to start gRPC server: %s", std::string(status.message()).c_str());
|
||||
} else {
|
||||
LOG_INFO("App", "gRPC server started on port %d", config_.test_harness_port);
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR("App", "Failed to initialize gRPC server: %s", std::string(status.message()).c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
controller_ = std::make_unique<Controller>();
|
||||
|
||||
#ifdef YAZE_WITH_GRPC
|
||||
// Connect services to controller/editor manager
|
||||
if (canvas_automation_service_) {
|
||||
controller_->SetCanvasAutomationService(canvas_automation_service_.get());
|
||||
}
|
||||
#endif
|
||||
|
||||
// Process pending ROM load if we have one (from flags/config - non-WASM only)
|
||||
std::string start_path = config_.rom_file;
|
||||
|
||||
@@ -102,6 +64,58 @@ void Application::Initialize(const AppConfig& config) {
|
||||
if (!start_path.empty() && controller_->editor_manager()) {
|
||||
RunStartupActions();
|
||||
}
|
||||
|
||||
#ifdef YAZE_WITH_GRPC
|
||||
// Initialize gRPC server if enabled
|
||||
if (config_.enable_test_harness) {
|
||||
LOG_INFO("App", "Initializing gRPC automation services...");
|
||||
canvas_automation_service_ = std::make_unique<CanvasAutomationServiceImpl>();
|
||||
grpc_server_ = std::make_unique<YazeGRPCServer>();
|
||||
|
||||
auto rom_getter = [this]() { return controller_->GetCurrentRom(); };
|
||||
|
||||
if (controller_->editor_manager()) {
|
||||
auto emulator_service =
|
||||
std::make_unique<yaze::net::EmulatorServiceImpl>(
|
||||
&controller_->editor_manager()->emulator(),
|
||||
rom_getter);
|
||||
auto add_status =
|
||||
grpc_server_->AddService(std::move(emulator_service));
|
||||
if (!add_status.ok()) {
|
||||
LOG_ERROR("App", "Failed to attach emulator service: %s",
|
||||
std::string(add_status.message()).c_str());
|
||||
}
|
||||
} else {
|
||||
LOG_WARN("App", "EditorManager not ready; emulator gRPC disabled");
|
||||
}
|
||||
|
||||
// Initialize server with all services
|
||||
auto status = grpc_server_->Initialize(
|
||||
config_.test_harness_port,
|
||||
&yaze::test::TestManager::Get(),
|
||||
rom_getter,
|
||||
nullptr, // Version manager not ready
|
||||
nullptr, // Approval manager not ready
|
||||
canvas_automation_service_.get()
|
||||
);
|
||||
|
||||
if (status.ok()) {
|
||||
status = grpc_server_->StartAsync(); // Start in background thread
|
||||
if (!status.ok()) {
|
||||
LOG_ERROR("App", "Failed to start gRPC server: %s", std::string(status.message()).c_str());
|
||||
} else {
|
||||
LOG_INFO("App", "gRPC server started on port %d", config_.test_harness_port);
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR("App", "Failed to initialize gRPC server: %s", std::string(status.message()).c_str());
|
||||
}
|
||||
|
||||
// Connect services to controller/editor manager
|
||||
if (canvas_automation_service_) {
|
||||
controller_->SetCanvasAutomationService(canvas_automation_service_.get());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
#include "app/platform/sdl_compat.h"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
@@ -21,8 +25,17 @@ namespace yaze {
|
||||
|
||||
absl::Status Controller::OnEntry(std::string filename) {
|
||||
// Create window backend using factory (auto-selects SDL2 or SDL3)
|
||||
window_backend_ = platform::WindowBackendFactory::Create(
|
||||
platform::WindowBackendFactory::GetDefaultType());
|
||||
auto backend_type = platform::WindowBackendFactory::GetDefaultType();
|
||||
auto renderer_type = gfx::RendererFactory::GetDefaultBackendType();
|
||||
#if defined(__APPLE__) && (TARGET_OS_IPHONE == 1 || TARGET_IPHONE_SIMULATOR == 1)
|
||||
backend_type = platform::WindowBackendType::IOS;
|
||||
renderer_type = gfx::RendererBackendType::Metal;
|
||||
#endif
|
||||
|
||||
window_backend_ = platform::WindowBackendFactory::Create(backend_type);
|
||||
if (!window_backend_) {
|
||||
return absl::InternalError("Failed to create window backend");
|
||||
}
|
||||
|
||||
platform::WindowConfig config;
|
||||
config.title = "Yet Another Zelda3 Editor";
|
||||
@@ -32,7 +45,7 @@ absl::Status Controller::OnEntry(std::string filename) {
|
||||
RETURN_IF_ERROR(window_backend_->Initialize(config));
|
||||
|
||||
// Create renderer via factory (auto-selects SDL2 or SDL3)
|
||||
renderer_ = gfx::RendererFactory::Create();
|
||||
renderer_ = gfx::RendererFactory::Create(renderer_type);
|
||||
if (!window_backend_->InitializeRenderer(renderer_.get())) {
|
||||
return absl::InternalError("Failed to initialize renderer");
|
||||
}
|
||||
@@ -162,6 +175,11 @@ absl::Status Controller::OnLoad() {
|
||||
if (!show_menu_bar && editor_manager_.ui_coordinator()) {
|
||||
editor_manager_.ui_coordinator()->DrawMenuBarRestoreButton();
|
||||
}
|
||||
#else
|
||||
if (window_backend_) {
|
||||
window_backend_->NewImGuiFrame();
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
#endif
|
||||
gui::WidgetIdRegistry::Instance().BeginFrame();
|
||||
absl::Status update_status = editor_manager_.Update();
|
||||
@@ -192,7 +210,9 @@ void Controller::DoRender() const {
|
||||
// Gentle frame rate cap to prevent excessive CPU usage
|
||||
// Only delay if we're rendering faster than 144 FPS (< 7ms per frame)
|
||||
if (delta_time < 0.007f) {
|
||||
#if TARGET_OS_IPHONE != 1
|
||||
SDL_Delay(1); // Tiny delay to yield CPU without affecting ImGui timing
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "app/editor/agent/agent_chat.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
@@ -13,6 +14,7 @@
|
||||
#include "app/gui/core/theme_manager.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui/misc/cpp/imgui_stdlib.h"
|
||||
#include "util/platform_paths.h"
|
||||
#include "util/log.h"
|
||||
|
||||
#ifdef YAZE_WITH_JSON
|
||||
@@ -22,6 +24,27 @@
|
||||
namespace yaze {
|
||||
namespace editor {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string ResolveAgentChatHistoryPath() {
|
||||
auto agent_dir = util::PlatformPaths::GetAppDataSubdirectory("agent");
|
||||
if (agent_dir.ok()) {
|
||||
return (*agent_dir / "agent_chat_history.json").string();
|
||||
}
|
||||
auto docs_dir = util::PlatformPaths::GetUserDocumentsSubdirectory("agent");
|
||||
if (docs_dir.ok()) {
|
||||
return (*docs_dir / "agent_chat_history.json").string();
|
||||
}
|
||||
auto temp_dir = util::PlatformPaths::GetTempDirectory();
|
||||
if (temp_dir.ok()) {
|
||||
return (*temp_dir / "agent_chat_history.json").string();
|
||||
}
|
||||
return (std::filesystem::current_path() / "agent_chat_history.json")
|
||||
.string();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AgentChat::AgentChat() {
|
||||
// Default initialization
|
||||
}
|
||||
@@ -119,7 +142,7 @@ void AgentChat::RenderToolbar() {
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button(ICON_MD_SAVE " Save")) {
|
||||
std::string filepath = ".yaze/agent_chat_history.json";
|
||||
std::string filepath = ResolveAgentChatHistoryPath();
|
||||
if (auto status = SaveHistory(filepath); !status.ok()) {
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show("Failed to save history: " + std::string(status.message()), ToastType::kError);
|
||||
@@ -133,7 +156,7 @@ void AgentChat::RenderToolbar() {
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button(ICON_MD_FOLDER_OPEN " Load")) {
|
||||
std::string filepath = ".yaze/agent_chat_history.json";
|
||||
std::string filepath = ResolveAgentChatHistoryPath();
|
||||
if (auto status = LoadHistory(filepath); !status.ok()) {
|
||||
if (toast_manager_) {
|
||||
toast_manager_->Show("Failed to load history: " + std::string(status.message()), ToastType::kError);
|
||||
@@ -480,7 +503,13 @@ absl::Status AgentChat::SaveHistory(const std::string& filepath) {
|
||||
// Create directory if needed
|
||||
std::filesystem::path path(filepath);
|
||||
if (path.has_parent_path()) {
|
||||
std::filesystem::create_directories(path.parent_path());
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(path.parent_path(), ec);
|
||||
if (ec) {
|
||||
return absl::InternalError(
|
||||
absl::StrFormat("Failed to create history directory: %s",
|
||||
ec.message()));
|
||||
}
|
||||
}
|
||||
|
||||
std::ofstream file(filepath);
|
||||
|
||||
@@ -262,12 +262,19 @@ std::string AgentCollaborationCoordinator::GenerateSessionCode() const {
|
||||
}
|
||||
|
||||
std::filesystem::path AgentCollaborationCoordinator::SessionsDirectory() const {
|
||||
auto config_dir = util::PlatformPaths::GetConfigDirectory();
|
||||
if (!config_dir.ok()) {
|
||||
// Fallback to a local directory if config can't be determined.
|
||||
return fs::current_path() / ".yaze" / "agent" / "sessions";
|
||||
auto agent_dir = util::PlatformPaths::GetAppDataSubdirectory("agent");
|
||||
if (agent_dir.ok()) {
|
||||
return *agent_dir / "sessions";
|
||||
}
|
||||
return *config_dir / "agent" / "sessions";
|
||||
auto docs_dir = util::PlatformPaths::GetUserDocumentsSubdirectory("agent");
|
||||
if (docs_dir.ok()) {
|
||||
return *docs_dir / "sessions";
|
||||
}
|
||||
auto temp_dir = util::PlatformPaths::GetTempDirectory();
|
||||
if (temp_dir.ok()) {
|
||||
return *temp_dir / "agent" / "sessions";
|
||||
}
|
||||
return fs::current_path() / "agent" / "sessions";
|
||||
}
|
||||
|
||||
std::filesystem::path AgentCollaborationCoordinator::SessionFilePath(
|
||||
|
||||
@@ -1453,11 +1453,20 @@ absl::Status AgentEditor::ImportProfile(const std::filesystem::path& path) {
|
||||
}
|
||||
|
||||
std::filesystem::path AgentEditor::GetProfilesDirectory() const {
|
||||
auto config_dir = yaze::util::PlatformPaths::GetConfigDirectory();
|
||||
if (!config_dir.ok()) {
|
||||
return std::filesystem::current_path() / ".yaze" / "agent" / "profiles";
|
||||
auto agent_dir = yaze::util::PlatformPaths::GetAppDataSubdirectory("agent");
|
||||
if (agent_dir.ok()) {
|
||||
return *agent_dir / "profiles";
|
||||
}
|
||||
return *config_dir / "agent" / "profiles";
|
||||
auto docs_dir =
|
||||
yaze::util::PlatformPaths::GetUserDocumentsSubdirectory("agent");
|
||||
if (docs_dir.ok()) {
|
||||
return *docs_dir / "profiles";
|
||||
}
|
||||
auto temp_dir = yaze::util::PlatformPaths::GetTempDirectory();
|
||||
if (temp_dir.ok()) {
|
||||
return *temp_dir / "agent" / "profiles";
|
||||
}
|
||||
return std::filesystem::current_path() / "agent" / "profiles";
|
||||
}
|
||||
|
||||
absl::Status AgentEditor::EnsureProfilesDirectory() {
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
#include "app/gui/core/input.h"
|
||||
#include "dungeon_canvas_viewer.h"
|
||||
#include "dungeon_coordinates.h"
|
||||
#include "canvas/canvas_menu.h"
|
||||
#include "core/icons.h"
|
||||
#include "app/gui/canvas/canvas_menu.h"
|
||||
#include "app/gui/core/icons.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "editor/dungeon/object_selection.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
// Third-party library headers
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#include "absl/status/status.h"
|
||||
@@ -270,7 +274,8 @@ EditorManager::EditorManager()
|
||||
project_management_panel_->SetToastManager(&toast_manager_);
|
||||
project_management_panel_->SetSwapRomCallback([this]() {
|
||||
// Prompt user to select a new ROM for the project
|
||||
auto rom_path = util::FileDialogWrapper::ShowOpenFileDialog();
|
||||
auto rom_path = util::FileDialogWrapper::ShowOpenFileDialog(
|
||||
util::MakeRomFileDialogOptions(false));
|
||||
if (!rom_path.empty()) {
|
||||
current_project_.rom_filename = rom_path;
|
||||
auto status = current_project_.Save();
|
||||
@@ -1480,61 +1485,80 @@ void EditorManager::DrawMenuBar() {
|
||||
* 8. Update UI state and recent files
|
||||
*/
|
||||
absl::Status EditorManager::LoadRom() {
|
||||
auto file_name = util::FileDialogWrapper::ShowOpenFileDialog();
|
||||
if (file_name.empty()) {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
auto load_from_path = [this](const std::string& file_name) -> absl::Status {
|
||||
if (file_name.empty()) {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Check if this is a project file - route to project loading
|
||||
if (absl::StrContains(file_name, ".yaze")) {
|
||||
return OpenRomOrProject(file_name);
|
||||
}
|
||||
// Check if this is a project file - route to project loading
|
||||
if (absl::StrContains(file_name, ".yaze")) {
|
||||
return OpenRomOrProject(file_name);
|
||||
}
|
||||
|
||||
if (session_coordinator_->HasDuplicateSession(file_name)) {
|
||||
toast_manager_.Show("ROM already open in another session",
|
||||
editor::ToastType::kWarning);
|
||||
return absl::OkStatus();
|
||||
}
|
||||
if (session_coordinator_->HasDuplicateSession(file_name)) {
|
||||
toast_manager_.Show("ROM already open in another session",
|
||||
editor::ToastType::kWarning);
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Delegate ROM loading to RomFileManager
|
||||
Rom temp_rom;
|
||||
RETURN_IF_ERROR(rom_file_manager_.LoadRom(&temp_rom, file_name));
|
||||
// Delegate ROM loading to RomFileManager
|
||||
Rom temp_rom;
|
||||
RETURN_IF_ERROR(rom_file_manager_.LoadRom(&temp_rom, file_name));
|
||||
|
||||
auto session_or = session_coordinator_->CreateSessionFromRom(
|
||||
std::move(temp_rom), file_name);
|
||||
if (!session_or.ok()) {
|
||||
return session_or.status();
|
||||
}
|
||||
auto session_or = session_coordinator_->CreateSessionFromRom(
|
||||
std::move(temp_rom), file_name);
|
||||
if (!session_or.ok()) {
|
||||
return session_or.status();
|
||||
}
|
||||
|
||||
ConfigureEditorDependencies(GetCurrentEditorSet(), GetCurrentRom(),
|
||||
GetCurrentSessionId());
|
||||
ConfigureEditorDependencies(GetCurrentEditorSet(), GetCurrentRom(),
|
||||
GetCurrentSessionId());
|
||||
|
||||
// Initialize resource labels for LoadRom() - use defaults with current project settings
|
||||
auto& label_provider = zelda3::GetResourceLabels();
|
||||
label_provider.SetProjectLabels(¤t_project_.resource_labels);
|
||||
label_provider.SetPreferHMagicNames(
|
||||
current_project_.workspace_settings.prefer_hmagic_names);
|
||||
LOG_INFO("EditorManager", "Initialized ResourceLabelProvider for LoadRom");
|
||||
// Initialize resource labels for LoadRom() - use defaults with current project settings
|
||||
auto& label_provider = zelda3::GetResourceLabels();
|
||||
label_provider.SetProjectLabels(¤t_project_.resource_labels);
|
||||
label_provider.SetPreferHMagicNames(
|
||||
current_project_.workspace_settings.prefer_hmagic_names);
|
||||
LOG_INFO("EditorManager", "Initialized ResourceLabelProvider for LoadRom");
|
||||
|
||||
#ifdef YAZE_ENABLE_TESTING
|
||||
test::TestManager::Get().SetCurrentRom(GetCurrentRom());
|
||||
test::TestManager::Get().SetCurrentRom(GetCurrentRom());
|
||||
#endif
|
||||
|
||||
auto& manager = project::RecentFilesManager::GetInstance();
|
||||
manager.AddFile(file_name);
|
||||
manager.Save();
|
||||
auto& manager = project::RecentFilesManager::GetInstance();
|
||||
manager.AddFile(file_name);
|
||||
manager.Save();
|
||||
|
||||
RETURN_IF_ERROR(LoadAssets());
|
||||
RETURN_IF_ERROR(LoadAssets());
|
||||
|
||||
if (ui_coordinator_) {
|
||||
ui_coordinator_->SetWelcomeScreenVisible(false);
|
||||
if (ui_coordinator_) {
|
||||
ui_coordinator_->SetWelcomeScreenVisible(false);
|
||||
|
||||
// Show ROM load options dialog for ZSCustomOverworld and feature settings
|
||||
rom_load_options_dialog_.Open(GetCurrentRom());
|
||||
show_rom_load_options_ = true;
|
||||
}
|
||||
// Show ROM load options dialog for ZSCustomOverworld and feature settings
|
||||
rom_load_options_dialog_.Open(GetCurrentRom());
|
||||
show_rom_load_options_ = true;
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
};
|
||||
|
||||
#if defined(__APPLE__) && TARGET_OS_IOS == 1
|
||||
util::FileDialogWrapper::ShowOpenFileDialogAsync(
|
||||
util::MakeRomFileDialogOptions(false),
|
||||
[this, load_from_path](const std::string& file_name) {
|
||||
auto status = load_from_path(file_name);
|
||||
if (!status.ok()) {
|
||||
toast_manager_.Show(
|
||||
absl::StrFormat("Failed to load ROM: %s", status.message()),
|
||||
ToastType::kError);
|
||||
}
|
||||
});
|
||||
return absl::OkStatus();
|
||||
#else
|
||||
auto file_name = util::FileDialogWrapper::ShowOpenFileDialog(
|
||||
util::MakeRomFileDialogOptions(false));
|
||||
return load_from_path(file_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
absl::Status EditorManager::LoadAssets(uint64_t passed_handle) {
|
||||
@@ -1900,41 +1924,63 @@ absl::Status EditorManager::CreateNewProject(const std::string& template_name) {
|
||||
// Trigger ROM selection dialog - projects need a ROM to be useful
|
||||
// LoadRom() opens file dialog and shows ROM load options when ROM is loaded
|
||||
status = LoadRom();
|
||||
#if !(defined(__APPLE__) && TARGET_OS_IOS == 1)
|
||||
if (status.ok() && ui_coordinator_) {
|
||||
ui_coordinator_->SetWelcomeScreenVisible(false);
|
||||
ui_coordinator_->SetWelcomeScreenManuallyClosed(true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
absl::Status EditorManager::OpenProject() {
|
||||
auto open_project_from_path =
|
||||
[this](const std::string& file_path) -> absl::Status {
|
||||
if (file_path.empty()) {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
project::YazeProject new_project;
|
||||
RETURN_IF_ERROR(new_project.Open(file_path));
|
||||
|
||||
// Validate project
|
||||
auto validation_status = new_project.Validate();
|
||||
if (!validation_status.ok()) {
|
||||
toast_manager_.Show(absl::StrFormat("Project validation failed: %s",
|
||||
validation_status.message()),
|
||||
editor::ToastType::kWarning, 5.0f);
|
||||
|
||||
// Ask user if they want to repair
|
||||
popup_manager_->Show("Project Repair");
|
||||
}
|
||||
|
||||
current_project_ = std::move(new_project);
|
||||
|
||||
// Initialize VersionManager for the project
|
||||
version_manager_ =
|
||||
std::make_unique<core::VersionManager>(¤t_project_);
|
||||
version_manager_->InitializeGit();
|
||||
|
||||
return LoadProjectWithRom();
|
||||
};
|
||||
|
||||
#if defined(__APPLE__) && TARGET_OS_IOS == 1
|
||||
util::FileDialogWrapper::ShowOpenFileDialogAsync(
|
||||
util::FileDialogOptions{},
|
||||
[this, open_project_from_path](const std::string& file_path) {
|
||||
auto status = open_project_from_path(file_path);
|
||||
if (!status.ok()) {
|
||||
toast_manager_.Show(
|
||||
absl::StrFormat("Failed to open project: %s", status.message()),
|
||||
ToastType::kError);
|
||||
}
|
||||
});
|
||||
return absl::OkStatus();
|
||||
#else
|
||||
auto file_path = util::FileDialogWrapper::ShowOpenFileDialog();
|
||||
if (file_path.empty()) {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
project::YazeProject new_project;
|
||||
RETURN_IF_ERROR(new_project.Open(file_path));
|
||||
|
||||
// Validate project
|
||||
auto validation_status = new_project.Validate();
|
||||
if (!validation_status.ok()) {
|
||||
toast_manager_.Show(absl::StrFormat("Project validation failed: %s",
|
||||
validation_status.message()),
|
||||
editor::ToastType::kWarning, 5.0f);
|
||||
|
||||
// Ask user if they want to repair
|
||||
popup_manager_->Show("Project Repair");
|
||||
}
|
||||
|
||||
current_project_ = std::move(new_project);
|
||||
|
||||
// Initialize VersionManager for the project
|
||||
version_manager_ = std::make_unique<core::VersionManager>(¤t_project_);
|
||||
version_manager_->InitializeGit();
|
||||
|
||||
return LoadProjectWithRom();
|
||||
return open_project_from_path(file_path);
|
||||
#endif
|
||||
}
|
||||
|
||||
absl::Status EditorManager::LoadProjectWithRom() {
|
||||
@@ -1944,13 +1990,41 @@ absl::Status EditorManager::LoadProjectWithRom() {
|
||||
toast_manager_.Show(
|
||||
"Project has no ROM file configured. Please select a ROM.",
|
||||
editor::ToastType::kInfo);
|
||||
auto rom_path = util::FileDialogWrapper::ShowOpenFileDialog();
|
||||
#if defined(__APPLE__) && TARGET_OS_IOS == 1
|
||||
util::FileDialogWrapper::ShowOpenFileDialogAsync(
|
||||
util::MakeRomFileDialogOptions(false),
|
||||
[this](const std::string& rom_path) {
|
||||
if (rom_path.empty()) {
|
||||
return;
|
||||
}
|
||||
current_project_.rom_filename = rom_path;
|
||||
auto save_status = current_project_.Save();
|
||||
if (!save_status.ok()) {
|
||||
toast_manager_.Show(
|
||||
absl::StrFormat("Failed to update project ROM: %s",
|
||||
save_status.message()),
|
||||
ToastType::kError);
|
||||
return;
|
||||
}
|
||||
auto status = LoadProjectWithRom();
|
||||
if (!status.ok()) {
|
||||
toast_manager_.Show(
|
||||
absl::StrFormat("Failed to load project ROM: %s",
|
||||
status.message()),
|
||||
ToastType::kError);
|
||||
}
|
||||
});
|
||||
return absl::OkStatus();
|
||||
#else
|
||||
auto rom_path = util::FileDialogWrapper::ShowOpenFileDialog(
|
||||
util::MakeRomFileDialogOptions(false));
|
||||
if (rom_path.empty()) {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
current_project_.rom_filename = rom_path;
|
||||
// Save updated project
|
||||
RETURN_IF_ERROR(current_project_.Save());
|
||||
#endif
|
||||
}
|
||||
|
||||
// Load ROM from project
|
||||
@@ -1963,14 +2037,41 @@ absl::Status EditorManager::LoadProjectWithRom() {
|
||||
absl::StrFormat("Could not load ROM '%s': %s. Please select a new ROM.",
|
||||
current_project_.rom_filename, load_status.message()),
|
||||
editor::ToastType::kWarning, 5.0f);
|
||||
|
||||
auto rom_path = util::FileDialogWrapper::ShowOpenFileDialog();
|
||||
#if defined(__APPLE__) && TARGET_OS_IOS == 1
|
||||
util::FileDialogWrapper::ShowOpenFileDialogAsync(
|
||||
util::MakeRomFileDialogOptions(false),
|
||||
[this](const std::string& rom_path) {
|
||||
if (rom_path.empty()) {
|
||||
return;
|
||||
}
|
||||
current_project_.rom_filename = rom_path;
|
||||
auto save_status = current_project_.Save();
|
||||
if (!save_status.ok()) {
|
||||
toast_manager_.Show(
|
||||
absl::StrFormat("Failed to update project ROM: %s",
|
||||
save_status.message()),
|
||||
ToastType::kError);
|
||||
return;
|
||||
}
|
||||
auto status = LoadProjectWithRom();
|
||||
if (!status.ok()) {
|
||||
toast_manager_.Show(
|
||||
absl::StrFormat("Failed to load project ROM: %s",
|
||||
status.message()),
|
||||
ToastType::kError);
|
||||
}
|
||||
});
|
||||
return absl::OkStatus();
|
||||
#else
|
||||
auto rom_path = util::FileDialogWrapper::ShowOpenFileDialog(
|
||||
util::MakeRomFileDialogOptions(false));
|
||||
if (rom_path.empty()) {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
current_project_.rom_filename = rom_path;
|
||||
RETURN_IF_ERROR(current_project_.Save());
|
||||
RETURN_IF_ERROR(rom_file_manager_.LoadRom(&temp_rom, rom_path));
|
||||
#endif
|
||||
}
|
||||
|
||||
auto session_or = session_coordinator_->CreateSessionFromRom(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "app/gui/app/agent_chat_widget.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
@@ -8,6 +9,7 @@
|
||||
#include "absl/time/time.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui/misc/cpp/imgui_stdlib.h"
|
||||
#include "util/platform_paths.h"
|
||||
|
||||
#ifdef YAZE_WITH_JSON
|
||||
#include "nlohmann/json.hpp"
|
||||
@@ -17,6 +19,27 @@ namespace yaze {
|
||||
|
||||
namespace gui {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string ResolveAgentChatHistoryPath() {
|
||||
auto agent_dir = util::PlatformPaths::GetAppDataSubdirectory("agent");
|
||||
if (agent_dir.ok()) {
|
||||
return (*agent_dir / "agent_chat_history.json").string();
|
||||
}
|
||||
auto docs_dir = util::PlatformPaths::GetUserDocumentsSubdirectory("agent");
|
||||
if (docs_dir.ok()) {
|
||||
return (*docs_dir / "agent_chat_history.json").string();
|
||||
}
|
||||
auto temp_dir = util::PlatformPaths::GetTempDirectory();
|
||||
if (temp_dir.ok()) {
|
||||
return (*temp_dir / "agent_chat_history.json").string();
|
||||
}
|
||||
return (std::filesystem::current_path() / "agent_chat_history.json")
|
||||
.string();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AgentChatWidget::AgentChatWidget()
|
||||
: scroll_to_bottom_(false),
|
||||
auto_scroll_(true),
|
||||
@@ -99,7 +122,7 @@ void AgentChatWidget::RenderToolbar() {
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Save History")) {
|
||||
std::string filepath = ".yaze/agent_chat_history.json";
|
||||
std::string filepath = ResolveAgentChatHistoryPath();
|
||||
if (auto status = SaveHistory(filepath); !status.ok()) {
|
||||
std::cerr << "Failed to save history: " << status.message() << std::endl;
|
||||
} else {
|
||||
@@ -109,7 +132,7 @@ void AgentChatWidget::RenderToolbar() {
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Load History")) {
|
||||
std::string filepath = ".yaze/agent_chat_history.json";
|
||||
std::string filepath = ResolveAgentChatHistoryPath();
|
||||
if (auto status = LoadHistory(filepath); !status.ok()) {
|
||||
std::cerr << "Failed to load history: " << status.message() << std::endl;
|
||||
}
|
||||
@@ -297,6 +320,17 @@ absl::Status AgentChatWidget::SaveHistory(const std::string& filepath) {
|
||||
return absl::FailedPreconditionError("Agent service not initialized");
|
||||
}
|
||||
|
||||
std::filesystem::path path(filepath);
|
||||
if (path.has_parent_path()) {
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(path.parent_path(), ec);
|
||||
if (ec) {
|
||||
return absl::InternalError(
|
||||
absl::StrFormat("Failed to create history directory: %s",
|
||||
ec.message()));
|
||||
}
|
||||
}
|
||||
|
||||
std::ofstream file(filepath);
|
||||
if (!file.is_open()) {
|
||||
return absl::InternalError(
|
||||
|
||||
Reference in New Issue
Block a user