30 return absl::OkStatus();
33 std::vector<std::string> args;
34 for (
int i = 1; i < argc; ++i) {
35 args.push_back(argv[i]);
40 auto show_rom_subcommand_help = [&]() {
41 std::cout <<
"\n\033[1;36mROM subcommands:\033[0m\n";
42 std::cout <<
" z3ed rom info --rom=<path>\n";
43 std::cout <<
" z3ed rom validate --rom=<path>\n";
44 std::cout <<
" z3ed rom read --address=0x1000 --length=16 --rom=<path>\n";
45 std::cout <<
" z3ed rom write --address=0x1000 --value=0xFF --rom=<path>\n";
46 std::cout <<
" z3ed rom diff --rom_a=<a> --rom_b=<b>\n";
47 std::cout <<
" z3ed rom compare --rom=<path> --baseline=<path>\n";
48 std::cout <<
" z3ed rom doctor --rom=<path>\n\n";
49 std::cout <<
"Equivalent direct commands are available as `rom-*` entries:\n";
50 std::cout << registry.GenerateCategoryHelp(
"rom") <<
"\n";
53 auto show_debug_subcommand_help = []() {
54 std::cout <<
"\n\033[1;36mDebug subcommands:\033[0m\n";
55 std::cout <<
" z3ed debug state [--backend=mesen|grpc]\n";
56 std::cout <<
" z3ed debug sprites [--backend=mesen]\n";
57 std::cout <<
" z3ed debug cpu [--backend=mesen]\n";
58 std::cout <<
" z3ed debug mem read --address=<addr> [--length=<n>]\n";
59 std::cout <<
" z3ed debug mem write --address=<addr> --value=<hex>\n";
60 std::cout <<
" z3ed debug disasm --address=<addr> [--count=<n>]\n";
61 std::cout <<
" z3ed debug trace --address=<addr> [--count=<n>]\n";
62 std::cout <<
" z3ed debug breakpoint --address=<addr>\n";
63 std::cout <<
" z3ed debug control --action=<pause|resume|step|reset>\n";
64 std::cout <<
" z3ed debug reset [--backend=mesen|grpc]\n\n";
65 std::cout <<
"Tip: use `z3ed <debug-command> --help` for command-specific flags.\n";
68 if (args[0] ==
"help") {
69 if (args.size() > 1) {
70 const std::string& target = args[1];
71 if (target ==
"all") {
72 std::cout << registry.GenerateCompleteHelp() <<
"\n";
73 }
else if (registry.HasCommand(target)) {
74 std::cout << registry.GenerateHelp(target) <<
"\n";
81 return absl::OkStatus();
85 if (args[0] ==
"agent") {
86 if (args.size() < 2 || args[1] ==
"--help" || args[1] ==
"-h") {
87#ifdef YAZE_ENABLE_AGENT_CLI
88 std::cout <<
"\n\033[1;36mAgent command:\033[0m\n";
89 std::cout <<
" z3ed agent <subcommand> [flags]\n";
90 std::cout <<
" z3ed agent --help\n";
91 std::cout <<
"\nUse `z3ed agent <subcommand> --help` for scoped details.\n";
93 std::cout <<
"\n\033[1;36mAgent command:\033[0m\n";
94 std::cout <<
" This build was compiled without agent CLI support.\n";
95 std::cout <<
" Rebuild with `YAZE_ENABLE_AGENT_CLI` to enable `z3ed agent`.\n";
97 return absl::OkStatus();
99#ifdef YAZE_ENABLE_AGENT_CLI
100 std::vector<std::string> agent_args(args.begin() + 1, args.end());
103 return absl::FailedPreconditionError(
104 "Agent CLI is disabled in this build");
109 if (args[0] ==
"rom") {
110 if (args.size() < 2 || args[1] ==
"--help" || args[1] ==
"-h") {
111 show_rom_subcommand_help();
112 return absl::OkStatus();
115 const std::string& sub = args[1];
119 }
else if (sub ==
"write") {
120 mapped =
"rom-write";
121 }
else if (sub ==
"info") {
123 }
else if (sub ==
"validate") {
124 mapped =
"rom-validate";
125 }
else if (sub ==
"diff") {
127 }
else if (sub ==
"compare") {
128 mapped =
"rom-compare";
129 }
else if (sub ==
"doctor") {
130 mapped =
"rom-doctor";
132 std::cerr <<
"\n\033[1;31mError:\033[0m Unknown rom subcommand: " << sub
134 show_rom_subcommand_help();
135 return absl::InvalidArgumentError(
136 absl::StrCat(
"Unknown rom subcommand: ", sub));
139 std::vector<std::string> command_args(args.begin() + 2, args.end());
140 if (registry.HasCommand(mapped)) {
141 return registry.Execute(mapped, command_args,
nullptr);
143 return absl::NotFoundError(
144 absl::StrCat(
"Command not found for rom subcommand: ", mapped));
148 if (args[0] ==
"debug") {
149 if (args.size() < 2 || args[1] ==
"--help" || args[1] ==
"-h") {
150 show_debug_subcommand_help();
151 return absl::OkStatus();
154 std::string backend =
"mesen";
155 std::vector<std::string> filtered_args;
156 filtered_args.reserve(args.size());
157 filtered_args.push_back(args[0]);
158 for (
size_t i = 1; i < args.size(); ++i) {
159 const std::string& token = args[i];
160 if (absl::StartsWith(token,
"--backend=") ||
161 absl::StartsWith(token,
"--debug-backend=")) {
162 backend = token.substr(token.find(
'=') + 1);
165 if (token ==
"--backend" || token ==
"--debug-backend") {
166 if (i + 1 < args.size()) {
167 backend = args[i + 1];
172 filtered_args.push_back(token);
175 const std::string& topic = filtered_args[1];
178 auto require_grpc = [&]() -> absl::Status {
179 return absl::FailedPreconditionError(
180 "Requested gRPC backend, but this debug subcommand is not supported");
183 if (topic ==
"state" || topic ==
"gamestate") {
184 mapped = (backend ==
"grpc") ?
"emulator-get-state" :
"mesen-gamestate";
185 }
else if (topic ==
"sprites") {
186 if (backend ==
"grpc")
return require_grpc();
187 mapped =
"mesen-sprites";
188 }
else if (topic ==
"cpu") {
189 if (backend ==
"grpc")
return require_grpc();
190 mapped =
"mesen-cpu";
191 }
else if (topic ==
"mem" || topic ==
"memory") {
192 if (filtered_args.size() < 3) {
193 show_debug_subcommand_help();
194 return absl::InvalidArgumentError(
195 "debug mem requires read/write subcommand");
197 const std::string& action = filtered_args[2];
198 if (action ==
"read") {
200 (backend ==
"grpc") ?
"emulator-read-memory" :
"mesen-memory-read";
201 filtered_args.erase(filtered_args.begin() + 2);
202 }
else if (action ==
"write") {
204 (backend ==
"grpc") ?
"emulator-write-memory" :
"mesen-memory-write";
205 filtered_args.erase(filtered_args.begin() + 2);
207 show_debug_subcommand_help();
208 return absl::InvalidArgumentError(
209 "debug mem subcommand must be read or write");
211 }
else if (topic ==
"disasm") {
212 if (backend ==
"grpc")
return require_grpc();
213 mapped =
"mesen-disasm";
214 }
else if (topic ==
"trace") {
215 if (backend ==
"grpc")
return require_grpc();
216 mapped =
"mesen-trace";
217 }
else if (topic ==
"breakpoint" || topic ==
"bp") {
218 if (backend ==
"grpc")
return require_grpc();
219 mapped =
"mesen-breakpoint";
220 }
else if (topic ==
"control") {
221 if (backend ==
"grpc")
return require_grpc();
222 mapped =
"mesen-control";
223 }
else if (topic ==
"reset") {
224 mapped = (backend ==
"grpc") ?
"emulator-reset" :
"mesen-control";
225 if (backend !=
"grpc") {
226 filtered_args.push_back(
"--action=reset");
229 show_debug_subcommand_help();
230 return absl::InvalidArgumentError(
231 absl::StrCat(
"Unknown debug subcommand: ", topic));
234 std::vector<std::string> command_args(filtered_args.begin() + 2,
235 filtered_args.end());
236 if (registry.HasCommand(mapped)) {
237 return registry.Execute(mapped, command_args,
nullptr);
239 return absl::NotFoundError(
240 absl::StrCat(
"Command not found for debug subcommand: ", mapped));
243 std::string command_name = args[0];
244 std::vector<std::string> command_args(args.begin() + 1, args.end());
246 if (registry.HasCommand(command_name)) {
247 return registry.Execute(command_name, command_args,
nullptr);
250 if (!registry.GetCommandsInCategory(command_name).empty()) {
252 return absl::OkStatus();
255 return absl::NotFoundError(absl::StrCat(
"Unknown command: ", command_name));