fix(cli): take global flags after the command, and call --json again
Only --json was taken after the command, so `wait --paused --timeout
60s`, the order the guide's own synopsis and agents use, failed with
"unknown argument '--timeout'", and `-i` after the command did too.
And since that --json was taken as the output flag, `call X --json
'{...}'`, the documented way to pass arguments as JSON, never reached
call: its object then failed as "not key=value".
--timeout, -i and --json now go anywhere on the line; no command has
options of those names. After `call`, a --json followed by an object
is the arguments, and any other --json the output flag. A trailing
--timeout or -i without its value is a usage error that says so.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
6987033d6b
commit
7574ad5c4e
2 changed files with 23 additions and 4 deletions
|
|
@ -878,14 +878,20 @@ namespace {
|
||||||
for (std::size_t i = 0; i < args.size(); ++i) {
|
for (std::size_t i = 0; i < args.size(); ++i) {
|
||||||
const std::string_view arg = args[i];
|
const std::string_view arg = args[i];
|
||||||
if (!options.command.empty()) {
|
if (!options.command.empty()) {
|
||||||
// Global flags may follow the command too, before its own.
|
// Global flags go anywhere, as agents write them: `wait
|
||||||
if (arg == "--json") {
|
// --paused --timeout 60s`. No command has options of these
|
||||||
|
// names, but for `call --json '{...}'`, its arguments as JSON.
|
||||||
|
const bool callArguments = options.command == "call" && arg == "--json" && i + 1 < args.size() && args[i + 1].starts_with('{');
|
||||||
|
if (arg == "--json" && !callArguments) {
|
||||||
options.json = true;
|
options.json = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (arg != "--timeout" && arg != "-i" && arg != "--instance") {
|
||||||
options.rest.emplace_back(arg);
|
options.rest.emplace_back(arg);
|
||||||
|
if (callArguments) options.rest.emplace_back(args[++i]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if ((arg == "-i" || arg == "--instance") && i + 1 < args.size()) {
|
if ((arg == "-i" || arg == "--instance") && i + 1 < args.size()) {
|
||||||
options.instance = args[++i];
|
options.instance = args[++i];
|
||||||
} else if (arg == "--json") {
|
} else if (arg == "--json") {
|
||||||
|
|
@ -897,6 +903,9 @@ namespace {
|
||||||
return exitUsage;
|
return exitUsage;
|
||||||
}
|
}
|
||||||
options.timeout = *timeout;
|
options.timeout = *timeout;
|
||||||
|
} else if (arg == "--timeout" || arg == "-i" || arg == "--instance") {
|
||||||
|
*env.err << std::format("crafter-debug: {} needs a value\n", arg);
|
||||||
|
return exitUsage;
|
||||||
} else if (arg == "-h" || arg == "--help") {
|
} else if (arg == "-h" || arg == "--help") {
|
||||||
*env.out << usage;
|
*env.out << usage;
|
||||||
return exitOk;
|
return exitOk;
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,10 @@ int main() {
|
||||||
Check(r.code == 0 && Has(r.out, "'score >= 1' held at frame"), "wait for a condition");
|
Check(r.code == 0 && Has(r.out, "'score >= 1' held at frame"), "wait for a condition");
|
||||||
r = Run({ "--timeout", "100ms", "wait", "score < 0" }, instances);
|
r = Run({ "--timeout", "100ms", "wait", "score < 0" }, instances);
|
||||||
Check(r.code == 5 && Has(r.err, "was not true within"), "a wait that times out exits 5 and says what the paths were");
|
Check(r.code == 5 && Has(r.err, "was not true within"), "a wait that times out exits 5 and says what the paths were");
|
||||||
|
r = Run({ "wait", "score < 0", "--timeout", "100ms" }, instances);
|
||||||
|
Check(r.code == 5 && Has(r.err, "was not true within"), std::format("global flags also go after the command's own ({})", r.err));
|
||||||
|
r = Run({ "wait", "--frames", "1", "--timeout" }, instances);
|
||||||
|
Check(r.code == 2 && Has(r.err, "--timeout needs a value"), "a global flag without its value is a usage error");
|
||||||
|
|
||||||
r = Run({ "log", "--last", "5" }, instances);
|
r = Run({ "log", "--last", "5" }, instances);
|
||||||
Check(r.code == 0 && Has(r.out, "AGENT"), "log shows the agent's actions");
|
Check(r.code == 0 && Has(r.out, "AGENT"), "log shows the agent's actions");
|
||||||
|
|
@ -178,6 +182,12 @@ int main() {
|
||||||
} catch (const ParseError&) {
|
} catch (const ParseError&) {
|
||||||
}
|
}
|
||||||
Check(r.code == 0 && json, "--json prints JSON");
|
Check(r.code == 0 && json, "--json prints JSON");
|
||||||
|
r = Run({ "status", "--json" }, instances);
|
||||||
|
Check(r.code == 0 && r.out.starts_with("{"), "--json after the command too");
|
||||||
|
r = Run({ "call", "Player_SetAim", "--json", R"({"slot": 4, "yaw": 5})" }, instances);
|
||||||
|
Check(r.code == 0 && Has(r.out, R"({"slot":4,"yaw":5.0})"), std::format("call takes its arguments as JSON ({})", r.out + r.err));
|
||||||
|
r = Run({ "call", "Player_SetAim", "--json", R"({"slot": 4})", "yaw=7", "--json" }, instances);
|
||||||
|
Check(r.code == 0 && Has(r.out, R"({"slot":4,"yaw":7.0})"), std::format("JSON arguments with key=value on top, and --json after them ({})", r.out + r.err));
|
||||||
|
|
||||||
r = Run({ "stauts" }, instances);
|
r = Run({ "stauts" }, instances);
|
||||||
Check(r.code == 2 && Has(r.err, "did you mean 'status'"), "a mistyped command name gets a suggestion");
|
Check(r.code == 2 && Has(r.err, "did you mean 'status'"), "a mistyped command name gets a suggestion");
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue