1#include "cli/handlers/commands.h"
12#include "absl/flags/declare.h"
13#include "absl/flags/flag.h"
14#include "absl/status/status.h"
15#include "absl/status/status.h"
16#include "absl/strings/ascii.h"
17#include "absl/strings/match.h"
18#include "absl/strings/str_cat.h"
19#include "absl/strings/str_format.h"
20#include "absl/strings/str_join.h"
21#include "absl/time/clock.h"
22#include "absl/time/time.h"
23#include "absl/strings/string_view.h"
55 std::string format =
"json";
57 std::string version =
"0.1.0";
66 auto project_status = project.
Open(
".");
68 if (project_status.ok()) {
69 std::cout <<
"š Loaded project: " << project.
name <<
"\n";
73 if (labels_status.ok()) {
74 std::cout <<
"ā
Embedded labels initialized (all Zelda3 resources available)\n";
81 std::cout <<
"š·ļø Loaded custom labels from: " << project.
labels_filename <<
"\n";
88 label_mgr->labels_loaded_ =
true;
89 std::cout <<
"š·ļø Using embedded Zelda3 labels (rooms, sprites, entrances, items, etc.)\n";
94 std::cout <<
"ā¹ļø No project file found. Using embedded default Zelda3 labels.\n";
98 return absl::OkStatus();
103 return absl::OkStatus();
106 std::string rom_path = absl::GetFlag(FLAGS_rom);
107 if (rom_path.empty()) {
108 return absl::FailedPreconditionError(
110 "No ROM loaded. Pass --rom=<path> when running %s.\n"
111 "Example: z3ed %s --rom=zelda3.sfc",
118 return absl::FailedPreconditionError(absl::StrFormat(
119 "Failed to load ROM from '%s': %s", rom_path, status.message()));
122 return absl::OkStatus();
126 const std::vector<std::string>& args) {
128 for (
size_t i = 0; i < args.size(); ++i) {
129 const std::string& token = args[i];
130 std::string flag = token;
131 std::optional<std::string> inline_value;
133 if (absl::StartsWith(token,
"--")) {
134 auto eq_pos = token.find(
'=');
135 if (eq_pos != std::string::npos) {
136 flag = token.substr(0, eq_pos);
137 inline_value = token.substr(eq_pos + 1);
142 [&](absl::string_view flag_name) -> absl::StatusOr<std::string> {
143 if (inline_value.has_value()) {
144 return *inline_value;
146 if (i + 1 >= args.size()) {
147 return absl::InvalidArgumentError(
148 absl::StrFormat(
"Flag %s requires a value", flag_name));
153 if (flag ==
"--resource") {
155 options.
resource = std::move(value);
156 }
else if (flag ==
"--format") {
158 options.
format = std::move(value);
159 }
else if (flag ==
"--output") {
162 }
else if (flag ==
"--version") {
164 options.
version = std::move(value);
165 }
else if (flag ==
"--last-updated") {
169 return absl::InvalidArgumentError(
170 absl::StrFormat(
"Unknown flag for agent describe: %s", token));
175 if (options.
format !=
"json" && options.
format !=
"yaml") {
176 return absl::InvalidArgumentError(
"--format must be either json or yaml");
186 if (arg_vec.size() < 2 || arg_vec[0] !=
"--prompt") {
187 return absl::InvalidArgumentError(
"Usage: agent run --prompt <prompt>");
189 std::string prompt = arg_vec[1];
191 RETURN_IF_ERROR(EnsureRomLoaded(rom,
"agent run --prompt \"<prompt>\""));
195 auto response_or = ai_service->GenerateResponse(prompt);
196 if (!response_or.ok()) {
197 return response_or.status();
201 return absl::FailedPreconditionError(
202 "Agent response did not include any executable commands.");
205 std::string provider = absl::GetFlag(FLAGS_ai_provider);
217 const auto& metadata = proposal_result.metadata;
218 std::filesystem::path proposal_dir = metadata.log_path.parent_path();
221 <<
"ā
Agent successfully planned and executed changes in a sandbox."
223 std::cout <<
" Proposal ID: " << metadata.id << std::endl;
224 std::cout <<
" Sandbox ROM: " << metadata.sandbox_rom_path << std::endl;
225 std::cout <<
" Proposal dir: " << proposal_dir << std::endl;
226 std::cout <<
" Diff file: " << metadata.diff_path << std::endl;
227 std::cout <<
" Log file: " << metadata.log_path << std::endl;
228 std::cout <<
" Proposal JSON: " << proposal_result.proposal_json_path
230 std::cout <<
" Commands executed: "
231 << proposal_result.executed_commands << std::endl;
232 std::cout <<
" Tile16 changes: " << proposal_result.change_count
234 std::cout <<
"\nTo review the changes, run:\n";
235 std::cout <<
" z3ed agent diff --proposal-id " << metadata.id << std::endl;
236 std::cout <<
"\nTo accept the changes, run:\n";
237 std::cout <<
" z3ed agent accept --proposal-id " << metadata.id << std::endl;
239 return absl::OkStatus();
243 if (arg_vec.size() < 2 || arg_vec[0] !=
"--prompt") {
244 return absl::InvalidArgumentError(
"Usage: agent plan --prompt <prompt>");
246 std::string prompt = arg_vec[1];
249 auto response_or = ai_service->GenerateResponse(prompt);
250 if (!response_or.ok()) {
251 return response_or.status();
253 std::vector<std::string> commands = response_or.value().commands;
259 if (!proposal_or.ok()) {
260 return proposal_or.status();
262 auto proposal = proposal_or.value();
265 auto plans_dir = registry.RootDirectory() /
"plans";
267 std::filesystem::create_directories(plans_dir, ec);
269 return absl::InternalError(absl::StrCat(
"Failed to create plans directory: ", ec.message()));
272 auto plan_path = plans_dir / (proposal.id +
".json");
273 auto save_status = generator.
SaveProposal(proposal, plan_path.string());
274 if (!save_status.ok()) {
278 std::cout <<
"AI Agent Plan (Proposal ID: " << proposal.id <<
"):\n";
279 std::cout << proposal.ToJson() << std::endl;
280 std::cout <<
"\nā
Plan saved to: " << plan_path.string() << std::endl;
282 return absl::OkStatus();
286 std::optional<std::string> proposal_id;
287 for (
size_t i = 0; i < args.size(); ++i) {
288 const std::string& token = args[i];
289 if (absl::StartsWith(token,
"--proposal-id=")) {
290 proposal_id = token.substr(14);
291 }
else if (token ==
"--proposal-id" && i + 1 < args.size()) {
292 proposal_id = args[i + 1];
298 absl::StatusOr<ProposalRegistry::ProposalMetadata> proposal_or;
299 if (proposal_id.has_value()) {
300 proposal_or = registry.GetProposal(proposal_id.value());
302 proposal_or = registry.GetLatestPendingProposal();
305 if (proposal_or.ok()) {
306 const auto& proposal = proposal_or.value();
308 std::cout <<
"\n=== Proposal Diff ===\n";
309 std::cout <<
"Proposal ID: " << proposal.id <<
"\n";
310 std::cout <<
"Sandbox ID: " << proposal.sandbox_id <<
"\n";
311 std::cout <<
"Prompt: " << proposal.prompt <<
"\n";
312 std::cout <<
"Description: " << proposal.description <<
"\n";
313 std::cout <<
"Status: ";
314 switch (proposal.status) {
316 std::cout <<
"Pending";
319 std::cout <<
"Accepted";
322 std::cout <<
"Rejected";
326 std::cout <<
"Created: " << absl::FormatTime(proposal.created_at) <<
"\n";
327 std::cout <<
"Commands Executed: " << proposal.commands_executed <<
"\n";
328 std::cout <<
"Bytes Changed: " << proposal.bytes_changed <<
"\n\n";
330 if (!proposal.sandbox_rom_path.empty()) {
331 std::cout <<
"Sandbox ROM: " << proposal.sandbox_rom_path <<
"\n";
333 std::cout <<
"Proposal directory: "
334 << proposal.log_path.parent_path() <<
"\n";
335 std::cout <<
"Diff file: " << proposal.diff_path <<
"\n";
336 std::cout <<
"Log file: " << proposal.log_path <<
"\n\n";
338 if (std::filesystem::exists(proposal.diff_path)) {
339 std::cout <<
"--- Diff Content ---\n";
340 std::ifstream diff_file(proposal.diff_path);
341 if (diff_file.is_open()) {
343 while (std::getline(diff_file, line)) {
344 std::cout << line <<
"\n";
347 std::cout <<
"(Unable to read diff file)\n";
350 std::cout <<
"(No diff file found)\n";
353 std::cout <<
"\n--- Execution Log ---\n";
354 if (std::filesystem::exists(proposal.log_path)) {
355 std::ifstream log_file(proposal.log_path);
356 if (log_file.is_open()) {
359 while (std::getline(log_file, line)) {
360 std::cout << line <<
"\n";
362 if (line_count > 50) {
363 std::cout <<
"... (log truncated, see " << proposal.log_path
364 <<
" for full output)\n";
369 std::cout <<
"(Unable to read log file)\n";
372 std::cout <<
"(No log file found)\n";
375 std::cout <<
"\n=== Next Steps ===\n";
376 std::cout <<
"To accept changes: z3ed agent commit\n";
377 std::cout <<
"To reject changes: z3ed agent revert\n";
378 std::cout <<
"To review in GUI: yaze --proposal=" << proposal.id <<
"\n";
380 return absl::OkStatus();
385 if (!sandbox_or.ok()) {
386 return absl::NotFoundError(
387 "No pending proposals found and no active sandbox. Run 'z3ed agent "
392 auto status = absl::UnimplementedError(
"RomDiff not yet implemented in new CommandHandler system");
397 return absl::AbortedError(
"No ROM loaded.");
399 return absl::OkStatus();
404 static bool initialized =
false;
409 std::cerr <<
"Failed to initialize learned knowledge service: "
410 << status.message() << std::endl;
418 std::cout <<
"\nUsage: z3ed agent learn [options]\n\n";
419 std::cout <<
"Options:\n";
420 std::cout <<
" --preference <key>=<value> Set a preference\n";
421 std::cout <<
" --get-preference <key> Get a preference value\n";
422 std::cout <<
" --list-preferences List all preferences\n";
423 std::cout <<
" --pattern <type> --data <json> Learn a ROM pattern\n";
424 std::cout <<
" --query-patterns <type> Query learned patterns\n";
425 std::cout <<
" --project <name> --context <text> Save project context\n";
426 std::cout <<
" --get-project <name> Get project context\n";
427 std::cout <<
" --list-projects List all projects\n";
428 std::cout <<
" --memory <topic> --summary <text> Store conversation memory\n";
429 std::cout <<
" --search-memories <query> Search memories\n";
430 std::cout <<
" --recent-memories [limit] Show recent memories\n";
431 std::cout <<
" --export <file> Export all data to JSON\n";
432 std::cout <<
" --import <file> Import data from JSON\n";
433 std::cout <<
" --stats Show statistics\n";
434 std::cout <<
" --clear Clear all learned data\n";
435 return absl::OkStatus();
439 std::string command = args[0];
441 if (command ==
"--preference" && args.size() >= 2) {
442 std::string pref = args[1];
443 size_t eq_pos = pref.find(
'=');
444 if (eq_pos == std::string::npos) {
445 return absl::InvalidArgumentError(
"Preference must be in format key=value");
447 std::string key = pref.substr(0, eq_pos);
448 std::string value = pref.substr(eq_pos + 1);
451 std::cout <<
"ā Preference '" << key <<
"' set to '" << value <<
"'\n";
456 if (command ==
"--get-preference" && args.size() >= 2) {
459 std::cout << args[1] <<
" = " << *value <<
"\n";
461 std::cout <<
"Preference '" << args[1] <<
"' not found\n";
463 return absl::OkStatus();
466 if (command ==
"--list-preferences") {
469 std::cout <<
"No preferences stored.\n";
471 std::cout <<
"\n=== Stored Preferences ===\n";
472 for (
const auto& [key, value] : prefs) {
473 std::cout <<
" " << key <<
" = " << value <<
"\n";
476 return absl::OkStatus();
479 if (command ==
"--stats") {
480 auto stats = learn_service.
GetStats();
481 std::cout <<
"\n=== Learned Knowledge Statistics ===\n";
483 std::cout <<
" ROM Patterns: " << stats.pattern_count <<
"\n";
484 std::cout <<
" Projects: " << stats.project_count <<
"\n";
485 std::cout <<
" Memories: " << stats.memory_count <<
"\n";
486 std::cout <<
" First learned: " << absl::FormatTime(absl::FromUnixMillis(stats.first_learned_at)) <<
"\n";
487 std::cout <<
" Last updated: " << absl::FormatTime(absl::FromUnixMillis(stats.last_updated_at)) <<
"\n";
488 return absl::OkStatus();
491 if (command ==
"--export" && args.size() >= 2) {
494 return json.status();
496 std::ofstream file(args[1]);
497 if (!file.is_open()) {
498 return absl::InternalError(
"Failed to open file for writing");
501 std::cout <<
"ā Exported learned data to " << args[1] <<
"\n";
502 return absl::OkStatus();
505 if (command ==
"--import" && args.size() >= 2) {
506 std::ifstream file(args[1]);
507 if (!file.is_open()) {
508 return absl::NotFoundError(
"File not found: " + args[1]);
510 std::stringstream buffer;
511 buffer << file.rdbuf();
514 std::cout <<
"ā Imported learned data from " << args[1] <<
"\n";
519 if (command ==
"--clear") {
520 auto status = learn_service.
ClearAll();
522 std::cout <<
"ā All learned data cleared\n";
527 if (command ==
"--list-projects") {
529 if (projects.empty()) {
530 std::cout <<
"No projects stored.\n";
532 std::cout <<
"\n=== Stored Projects ===\n";
533 for (
const auto& proj : projects) {
534 std::cout <<
" " << proj.project_name <<
"\n";
535 std::cout <<
" ROM Hash: " << proj.rom_hash.substr(0, 16) <<
"...\n";
536 std::cout <<
" Last Accessed: " << absl::FormatTime(absl::FromUnixMillis(proj.last_accessed)) <<
"\n";
539 return absl::OkStatus();
542 if (command ==
"--recent-memories") {
544 if (args.size() >= 2) {
545 limit = std::stoi(args[1]);
548 if (memories.empty()) {
549 std::cout <<
"No memories stored.\n";
551 std::cout <<
"\n=== Recent Memories ===\n";
552 for (
const auto& mem : memories) {
553 std::cout <<
" Topic: " << mem.topic <<
"\n";
554 std::cout <<
" Summary: " << mem.summary <<
"\n";
555 std::cout <<
" Facts: " << mem.key_facts.size() <<
" key facts\n";
556 std::cout <<
" Created: " << absl::FormatTime(absl::FromUnixMillis(mem.created_at)) <<
"\n";
560 return absl::OkStatus();
563 return absl::InvalidArgumentError(
"Unknown learn command. Use 'z3ed agent learn' for usage.");
568 auto proposals = registry.ListProposals();
570 if (proposals.empty()) {
571 std::cout <<
"No proposals found.\n";
573 <<
"Run 'z3ed agent run --prompt \"...\"' to create a proposal.\n";
574 return absl::OkStatus();
577 std::cout <<
"\n=== Agent Proposals ===\n\n";
579 for (
const auto& proposal : proposals) {
580 std::cout <<
"ID: " << proposal.id <<
"\n";
581 std::cout <<
" Status: ";
582 switch (proposal.status) {
584 std::cout <<
"Pending";
587 std::cout <<
"Accepted";
590 std::cout <<
"Rejected";
594 std::cout <<
" Created: " << absl::FormatTime(proposal.created_at) <<
"\n";
595 std::cout <<
" Prompt: " << proposal.prompt <<
"\n";
596 std::cout <<
" Commands: " << proposal.commands_executed <<
"\n";
597 std::cout <<
" Bytes Changed: " << proposal.bytes_changed <<
"\n";
601 std::cout <<
"Total: " << proposals.size() <<
" proposal(s)\n";
602 std::cout <<
"\nUse 'z3ed agent diff --proposal-id=<id>' to view details.\n";
604 return absl::OkStatus();
609 auto status = rom.
SaveToFile({.save_new =
false});
613 std::cout <<
"ā
Changes committed successfully." << std::endl;
615 return absl::AbortedError(
"No ROM loaded.");
617 return absl::OkStatus();
626 std::cout <<
"ā
Changes reverted successfully." << std::endl;
628 return absl::AbortedError(
"No ROM loaded.");
630 return absl::OkStatus();
637 std::optional<ResourceSchema> resource_schema;
638 if (options.resource.has_value()) {
639 auto resource_or = catalog.GetResource(*options.resource);
640 if (!resource_or.ok()) {
641 return resource_or.status();
643 resource_schema = resource_or.value();
647 if (options.format ==
"json") {
648 if (resource_schema.has_value()) {
649 payload = catalog.SerializeResource(*resource_schema);
651 payload = catalog.SerializeResources(catalog.AllResources());
654 std::string last_updated =
655 options.last_updated.has_value()
656 ? *options.last_updated
657 : absl::FormatTime(
"%Y-%m-%d", absl::Now(), absl::LocalTimeZone());
658 if (resource_schema.has_value()) {
659 std::vector<ResourceSchema> schemas{*resource_schema};
660 payload = catalog.SerializeResourcesAsYaml(schemas, options.version,
663 payload = catalog.SerializeResourcesAsYaml(catalog.AllResources(),
664 options.version, last_updated);
668 if (options.output_path.has_value()) {
669 std::ofstream out(*options.output_path, std::ios::binary | std::ios::trunc);
670 if (!out.is_open()) {
671 return absl::InternalError(absl::StrFormat(
672 "Failed to open %s for writing", *options.output_path));
677 return absl::InternalError(absl::StrFormat(
"Failed to write schema to %s",
678 *options.output_path));
680 std::cout << absl::StrFormat(
"Wrote %s schema to %s", options.format,
681 *options.output_path)
683 return absl::OkStatus();
686 std::cout << payload << std::endl;
687 return absl::OkStatus();
694 auto _ = TryLoadProjectAndLabels(rom);
698 return absl::OkStatus();
702 Rom* rom,
bool quiet) {
705 auto _ = TryLoadProjectAndLabels(*rom);
707 std::optional<std::string> batch_file;
708 std::optional<std::string> single_message;
709 bool verbose =
false;
710 bool vim_mode =
false;
711 std::optional<std::string> format_option;
713 for (
size_t i = 0; i < arg_vec.size(); ++i) {
714 const std::string& arg = arg_vec[i];
715 if (absl::StartsWith(arg,
"--file=")) {
716 batch_file = arg.substr(7);
717 }
else if (arg ==
"--file" && i + 1 < arg_vec.size()) {
718 batch_file = arg_vec[++i];
719 }
else if (absl::StartsWith(arg,
"--format=")) {
720 format_option = arg.substr(9);
721 }
else if (arg ==
"--format" && i + 1 < arg_vec.size()) {
722 format_option = arg_vec[++i];
723 }
else if (arg ==
"--json") {
724 format_option =
"json";
725 }
else if (arg ==
"--markdown" || arg ==
"--md") {
726 format_option =
"markdown";
727 }
else if (arg ==
"--compact" || arg ==
"--raw") {
728 format_option =
"compact";
729 }
else if (arg ==
"--verbose" || arg ==
"-v") {
731 }
else if (arg ==
"--vim") {
733 }
else if (!absl::StartsWith(arg,
"--") && !single_message.has_value()) {
734 single_message = arg;
741 if (format_option.has_value()) {
742 std::string normalized = absl::AsciiStrToLower(*format_option);
743 if (normalized ==
"json") {
745 }
else if (normalized ==
"markdown" || normalized ==
"md") {
747 }
else if (normalized ==
"compact" || normalized ==
"raw") {
749 }
else if (normalized ==
"text" || normalized ==
"friendly" ||
750 normalized ==
"pretty") {
753 return absl::InvalidArgumentError(
754 absl::StrCat(
"Unsupported chat format: ", *format_option,
755 ". Supported formats: text, markdown, json, compact"));
763 if (batch_file.has_value()) {
764 std::ifstream file(*batch_file);
765 if (!file.is_open()) {
766 return absl::NotFoundError(absl::StrCat(
"Failed to open file: ", *batch_file));
769 std::cout <<
"Running batch session from: " << *batch_file << std::endl;
770 std::cout <<
"----------------------------------------\n\n";
774 while (std::getline(file, line)) {
776 std::string trimmed_line = std::string(absl::StripAsciiWhitespace(line));
777 if (trimmed_line.empty() || absl::StartsWith(trimmed_line,
"#")) {
781 std::cout <<
"Input [" << line_num <<
"]: " << trimmed_line << std::endl;
783 std::string response;
786 std::cerr <<
"Error processing line " << line_num <<
": " << status.message() << std::endl;
789 std::cout << response <<
"\n";
794 return absl::OkStatus();
795 }
else if (single_message.has_value()) {
796 std::string response;
801 std::cout << response <<
"\n";
802 return absl::OkStatus();
810 std::optional<std::string> proposal_id;
811 for (
size_t i = 0; i < arg_vec.size(); ++i) {
812 const std::string& token = arg_vec[i];
813 if (absl::StartsWith(token,
"--proposal-id=")) {
814 proposal_id = token.substr(14);
817 if (token ==
"--proposal-id" && i + 1 < arg_vec.size()) {
818 proposal_id = arg_vec[i + 1];
823 if (!proposal_id.has_value() || proposal_id->empty()) {
824 return absl::InvalidArgumentError(
825 "Usage: agent accept --proposal-id <proposal_id>");
832 std::cout <<
"Proposal '" << *proposal_id <<
"' is already accepted."
834 return absl::OkStatus();
837 if (metadata.sandbox_rom_path.empty()) {
838 return absl::FailedPreconditionError(absl::StrCat(
839 "Proposal '", *proposal_id,
840 "' is missing sandbox ROM metadata. Cannot accept."));
843 if (!std::filesystem::exists(metadata.sandbox_rom_path)) {
844 return absl::NotFoundError(absl::StrCat(
845 "Sandbox ROM not found at ", metadata.sandbox_rom_path.string()));
849 EnsureRomLoaded(rom,
"agent accept --proposal-id <proposal_id>"));
854 if (!sandbox_load_status.ok()) {
855 return absl::InternalError(absl::StrCat(
856 "Failed to load sandbox ROM: ", sandbox_load_status.message()));
859 if (rom.
size() != sandbox_rom.
size()) {
860 rom.
Expand(
static_cast<int>(sandbox_rom.
size()));
864 if (!copy_status.ok()) {
865 return absl::InternalError(absl::StrCat(
866 "Failed to copy sandbox ROM data: ", copy_status.message()));
869 auto save_status = rom.
SaveToFile({.save_new =
false});
870 if (!save_status.ok()) {
871 return absl::InternalError(absl::StrCat(
872 "Failed to save changes to main ROM: ", save_status.message()));
879 absl::StrCat(
"Proposal accepted and applied to ", rom.
filename())));
881 if (!metadata.sandbox_id.empty()) {
884 if (!remove_status.ok()) {
885 std::cerr <<
"Warning: Failed to remove sandbox '" << metadata.sandbox_id
886 <<
"': " << remove_status.message() <<
"\n";
890 std::cout <<
"ā
Proposal '" << *proposal_id <<
"' accepted and applied to '"
891 << rom.
filename() <<
"'." << std::endl;
892 std::cout <<
" Source sandbox ROM: " << metadata.sandbox_rom_path
895 return absl::OkStatus();
The Rom class is used to load, save, and modify Rom data.
absl::Status LoadFromFile(const std::string &filename, bool z3_load=true)
absl::Status WriteVector(int addr, std::vector< uint8_t > data)
absl::Status SaveToFile(const SaveSettings &settings)
core::ResourceLabelManager * resource_label()
static ProposalRegistry & Instance()
static const ResourceCatalog & Instance()
absl::Status RemoveSandbox(const std::string &id)
absl::StatusOr< SandboxMetadata > ActiveSandbox() const
static RomSandboxManager & Instance()
Generates and manages tile16 editing proposals.
absl::StatusOr< Tile16Proposal > GenerateFromCommands(const std::string &prompt, const std::vector< std::string > &commands, const std::string &ai_service, Rom *rom)
Generate a tile16 proposal from an AI-generated command list.
absl::Status SaveProposal(const Tile16Proposal &proposal, const std::string &path)
Save a proposal to a JSON file for later review.
Manages persistent learned information across agent sessions.
std::optional< std::string > GetPreference(const std::string &key) const
std::vector< ProjectContext > GetAllProjects() const
std::vector< ConversationMemory > GetRecentMemories(int limit=10) const
absl::Status ImportFromJSON(const std::string &json_data)
absl::Status Initialize()
absl::Status SetPreference(const std::string &key, const std::string &value)
absl::StatusOr< std::string > ExportToJSON() const
std::map< std::string, std::string > GetAllPreferences() const
Simple text-based chat session for AI agent interaction.
void SetRomContext(Rom *rom)
void SetConfig(const AgentConfig &config)
absl::Status RunInteractive()
absl::Status SendAndWaitForResponse(const std::string &message, std::string *response_out=nullptr)
ABSL_DECLARE_FLAG(std::string, rom)
#define RETURN_IF_ERROR(expression)
#define ASSIGN_OR_RETURN(type_variable_name, expression)
absl::Status EnsureRomLoaded(Rom &rom, const std::string &command)
absl::StatusOr< DescribeOptions > ParseDescribeArgs(const std::vector< std::string > &args)
absl::Status TryLoadProjectAndLabels(Rom &rom)
absl::Status HandleSimpleChatCommand(const std::vector< std::string > &arg_vec, Rom *rom, bool quiet)
absl::Status HandleLearnCommand(const std::vector< std::string > &args)
absl::StatusOr< ProposalCreationResult > CreateProposalFromAgentResponse(const ProposalCreationRequest &request)
absl::Status HandleAcceptCommand(const std::vector< std::string > &arg_vec, Rom &rom)
absl::Status HandleCommitCommand(Rom &rom)
absl::Status HandleRunCommand(const std::vector< std::string > &arg_vec, Rom &rom)
absl::Status HandleDescribeCommand(const std::vector< std::string > &args)
absl::Status HandleDiffCommand(Rom &rom, const std::vector< std::string > &args)
absl::Status HandleChatCommand(Rom &rom)
absl::Status HandleRevertCommand(Rom &rom)
absl::Status HandleListCommand()
absl::Status HandlePlanCommand(const std::vector< std::string > &args)
std::unique_ptr< AIService > CreateAIService()
Main namespace for the application.
static RomLoadOptions CliDefaults()
std::vector< std::string > commands
AgentOutputFormat output_format
const AgentResponse * response
std::string sandbox_label
std::optional< std::string > resource
std::optional< std::string > output_path
std::optional< std::string > last_updated
std::unordered_map< std::string, std::unordered_map< std::string, std::string > > labels_
Modern project structure with comprehensive settings consolidation.
absl::Status Open(const std::string &project_path)
std::unordered_map< std::string, std::unordered_map< std::string, std::string > > resource_labels
std::string labels_filename
absl::Status InitializeEmbeddedLabels()