Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ that may never merge. They are not releases and are not listed here.

## Unreleased

- When a coding agent runs `mapbox --help` (detected the same way as for
the `User-Agent`), the help opens with a two-line hint pointing at
`mapbox --schema`. Help for people, and for subcommands, is unchanged.

- **Breaking**: `--eta-type`, `--navigation-profile` and `--origin` removed
from `mapbox search category`. The category endpoint does not currently
return an ETA, so the flags were accepted but had no effect. A script
Expand Down
14 changes: 13 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ use spec::ServiceSpec;
/// single source for the Rust half rather than for all three.
const REPO_URL: &str = "https://github.com/mapbox/cli";

/// Opens the top-level help when an agent is driving the CLI. Agents explore
/// by chaining `--help` calls, one command at a time; `--schema` answers the
/// same question for every command in one document.
const AGENT_HELP_HINT: &str = "\
Agents: `mapbox --schema` describes every command, its arguments and the request it makes
as one JSON document. Use it instead of chaining --help calls.";

/// Rejects a value the spec says is a number, while still yielding a
/// `String`.
///
Expand Down Expand Up @@ -770,7 +777,12 @@ fn cli() -> u8 {
}
};

let app = build_app(&specs);
let mut app = build_app(&specs);
// Here rather than in `build_app`, which tests call directly and which
// should not depend on who happens to be running them.
if agent_detect::detect_agent().is_some() {
app = app.before_help(AGENT_HELP_HINT);
}
let argv = tilesets_cli::escape_passthrough_args(&app, raw_argv.clone());
// Parsing consumes the tree, and `--schema` still has to read it
// afterwards — so the parse gets the copy and `app` stays whole.
Expand Down
43 changes: 43 additions & 0 deletions tests/output_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,49 @@ fn help_is_never_wrapped() {
assert!(text.contains("--output"), "--output should be documented");
}

const AGENT_HINT: &str = "Agents: `mapbox --schema`";

/// An agent reading top-level help is pointed at `--schema` rather than left
/// to chain `--help` calls. Only there: subcommand help stays as it was.
#[test]
fn an_agent_is_pointed_at_the_schema() {
let out = command()
.env("CLAUDECODE", "1")
.arg("--help")
.output()
.expect("run mapbox");
assert!(out.status.success());
assert!(stdout(&out).contains(AGENT_HINT), "{}", stdout(&out));

let sub = command()
.env("CLAUDECODE", "1")
.args(["styles", "--help"])
.output()
.expect("run mapbox");
assert!(!stdout(&sub).contains(AGENT_HINT), "{}", stdout(&sub));
}

/// A person gets the help they always did. The environment is cleared rather
/// than having agent variables removed one by one: the suite itself often
/// runs under an agent, and `agent_detect` knows more variables than this
/// file should have to list.
#[test]
fn without_an_agent_the_help_has_no_hint() {
let home = sandbox_home();
let mut cmd = Command::new(env!("CARGO_BIN_EXE_mapbox"));
cmd.env_clear()
.env("HOME", &home)
.env("MAPBOX_CONFIG_DIR", home.join(".mapbox"));
// Windows processes expect this one; nothing reads it as an agent.
if let Some(root) = std::env::var_os("SystemRoot") {
cmd.env("SystemRoot", root);
}
let out = cmd.arg("--help").output().expect("run mapbox");

assert!(out.status.success());
assert!(!stdout(&out).contains(AGENT_HINT), "{}", stdout(&out));
}

/// An operation that can never succeed is not in the command surface, so it
/// answers exactly as a mistyped name does — same code, same shape, same
/// exit. Anything else would tell a caller which scopes exist while still
Expand Down
Loading