3#include "absl/strings/str_cat.h"
4#include "absl/strings/str_format.h"
5#include "absl/strings/str_join.h"
13 static bool initialized =
false;
23 std::string name = handler->GetName();
29 for (
const auto& alias : metadata.
aliases) {
41 return it->second.get();
47 auto handler_it =
handlers_.find(alias_it->second);
49 return handler_it->second.get();
57 const std::string& name)
const {
59 std::string canonical_name = name;
62 canonical_name = alias_it->second;
66 return (it !=
metadata_.end()) ? &it->second :
nullptr;
70 const std::string& category)
const {
71 std::vector<std::string> result;
72 for (
const auto& [name, metadata] :
metadata_) {
73 if (metadata.category == category) {
74 result.push_back(name);
81 std::vector<std::string> categories;
82 for (
const auto& [_, metadata] :
metadata_) {
83 if (std::find(categories.begin(), categories.end(), metadata.category) == categories.end()) {
84 categories.push_back(metadata.category);
91 std::vector<std::string> result;
92 for (
const auto& [name, metadata] :
metadata_) {
93 if (metadata.available_to_agent) {
94 result.push_back(name);
109 return absl::StrFormat(
"Command '%s' not found", name);
112 std::ostringstream help;
113 help <<
"\n\033[1;36m" << metadata->name <<
"\033[0m - " << metadata->description <<
"\n\n";
114 help <<
"\033[1;33mUsage:\033[0m\n";
115 help <<
" " << metadata->usage <<
"\n\n";
117 if (!metadata->examples.empty()) {
118 help <<
"\033[1;33mExamples:\033[0m\n";
119 for (
const auto& example : metadata->examples) {
120 help <<
" " << example <<
"\n";
125 if (metadata->requires_rom) {
126 help <<
"\033[1;33mRequires:\033[0m ROM file (--rom=<path>)\n";
128 if (metadata->requires_grpc) {
129 help <<
"\033[1;33mRequires:\033[0m YAZE running with gRPC enabled\n";
132 if (!metadata->aliases.empty()) {
133 help <<
"\n\033[1;33mAliases:\033[0m " << absl::StrJoin(metadata->aliases,
", ") <<
"\n";
141 if (commands.empty()) {
142 return absl::StrFormat(
"No commands in category '%s'", category);
145 std::ostringstream help;
146 help <<
"\n\033[1;36m" << category <<
" commands:\033[0m\n\n";
148 for (
const auto& cmd : commands) {
151 help <<
" \033[1;33m" << cmd <<
"\033[0m\n";
152 help <<
" " << metadata->description <<
"\n";
153 if (!metadata->usage.empty()) {
154 help <<
" Usage: " << metadata->usage <<
"\n";
164 std::ostringstream help;
165 help <<
"\n\033[1;36mAll z3ed Commands:\033[0m\n\n";
168 for (
const auto& category : categories) {
176 const std::vector<std::string>& args,
178 auto* handler =
Get(name);
180 return absl::NotFoundError(absl::StrFormat(
"Command '%s' not found", name));
183 return handler->Run(args, rom_context);
187 return Get(name) !=
nullptr;
194 for (
auto& handler : all_handlers) {
195 std::string name = handler->GetName();
199 metadata.
name = name;
200 metadata.
usage = handler->GetUsage();
206 if (name.find(
"resource-") == 0) {
208 metadata.
description =
"Resource inspection and search";
209 if (name ==
"resource-list") {
211 "z3ed resource-list --type=dungeon --format=json",
212 "z3ed resource-list --type=sprite --format=table"
215 }
else if (name.find(
"dungeon-") == 0) {
217 metadata.
description =
"Dungeon inspection and editing";
218 if (name ==
"dungeon-describe-room") {
220 "z3ed dungeon-describe-room --room=5 --format=json"
223 }
else if (name.find(
"overworld-") == 0) {
225 metadata.
description =
"Overworld inspection and editing";
226 if (name ==
"overworld-find-tile") {
228 "z3ed overworld-find-tile --tile=0x42 --format=json"
231 }
else if (name.find(
"emulator-") == 0) {
233 metadata.
description =
"Emulator control and debugging";
235 if (name ==
"emulator-set-breakpoint") {
237 "z3ed emulator-set-breakpoint --address=0x83D7 --description='NMI handler'"
240 }
else if (name.find(
"gui-") == 0) {
244 }
else if (name.find(
"hex-") == 0) {
247 }
else if (name.find(
"palette-") == 0) {
250 }
else if (name.find(
"sprite-") == 0) {
253 }
else if (name.find(
"message-") == 0 || name.find(
"dialogue-") == 0) {
255 metadata.
description = name.find(
"message-") == 0 ?
"Message inspection" :
"Dialogue inspection";
256 }
else if (name.find(
"music-") == 0) {
259 }
else if (name ==
"simple-chat" || name ==
"chat") {
265 "z3ed simple-chat --rom=zelda3.sfc",
266 "z3ed simple-chat \"What dungeons exist?\" --rom=zelda3.sfc"
273 Register(std::move(handler), metadata);
The Rom class is used to load, save, and modify Rom data.
Single source of truth for all z3ed commands.
std::map< std::string, std::string > aliases_
std::vector< std::string > GetCommandsInCategory(const std::string &category) const
Get all commands in a category.
static CommandRegistry & Instance()
std::string GenerateCategoryHelp(const std::string &category) const
Generate category help text.
void RegisterAllCommands()
std::string ExportFunctionSchemas() const
Export function schemas for AI tool calling (JSON)
const CommandMetadata * GetMetadata(const std::string &name) const
Get command metadata.
absl::Status Execute(const std::string &name, const std::vector< std::string > &args, Rom *rom_context=nullptr)
Execute a command by name.
std::string GenerateCompleteHelp() const
Generate complete help text (all commands)
std::vector< std::string > GetAgentCommands() const
Get all commands available to AI agents.
std::map< std::string, CommandMetadata > metadata_
std::map< std::string, std::unique_ptr< resources::CommandHandler > > handlers_
resources::CommandHandler * Get(const std::string &name) const
Get a command handler by name or alias.
bool HasCommand(const std::string &name) const
Check if command exists.
std::vector< std::string > GetCategories() const
Get all categories.
void Register(std::unique_ptr< resources::CommandHandler > handler, const CommandMetadata &metadata)
Register a command handler.
std::string GenerateHelp(const std::string &name) const
Generate help text for a command.
Base class for CLI command handlers.
std::vector< std::unique_ptr< resources::CommandHandler > > CreateAllCommandHandlers()
Factory function to create all command handlers (CLI + agent)
Main namespace for the application.