tool:run masks the failure message: getOutputValues() throws on unset outputs of a failed tool
## Problem
`drush tool:run` shows nothing useful when a tool fails. Instead of the failure message, it throws a `ContextException` and exits.
The command reads the result, then unconditionally reads the outputs:
```php
$success = $tool->getResultStatus();
$message = (string) $tool->getResultMessage();
$outputs = $tool->getOutputValues();
```
A tool that returns `ExecutableResult::failure()` never sets its declared output contexts. `getOutputValues()` loops over every declared output and calls `getOutputValue()`, which throws on an unset context:
```php
throw new ContextException(sprintf("The provided context '%s' is not valid.", $name));
```
So the command dies at `getOutputValues()` — before it ever prints `$message`. Any tool that declares an output and can fail hits this. The actual failure reason is lost.
## Steps to reproduce
1. Write (or use) a tool that declares an `output_definitions` entry and returns `ExecutableResult::failure('some helpful message')` on bad input.
2. Run it with input that triggers the failure: `drush tool:run my_tool --input='{...}'`.
3. Instead of `Failed: some helpful message`, you get:
```
In TypedOutputsTrait.php line 59:
The provided context 'my_output' is not valid.
```
## Cause
`ToolRunCommand::runTool()` reads outputs regardless of whether the tool succeeded. The MCP bridge (`mcp_server_tool_bridge`) already does the right thing — it reads outputs only inside `if ($result->isSuccess())` — so the same failure surfaces its message correctly over MCP but not over the CLI.
## Proposed fix
Read outputs only on success, mirroring the bridge:
```php
$success = $tool->getResultStatus();
$message = (string) $tool->getResultMessage();
$outputs = $success ? $tool->getOutputValues() : [];
```
Patch attached below.
```diff
--- a/src/Drush/Commands/ToolRunCommand.php
+++ b/src/Drush/Commands/ToolRunCommand.php
@@ -141,7 +141,11 @@
// Get result.
$success = $tool->getResultStatus();
$message = (string) $tool->getResultMessage();
- $outputs = $tool->getOutputValues();
+ // Outputs are only populated on success. A failed tool leaves its declared
+ // output contexts unset, and getOutputValues() throws a ContextException on
+ // those, which would mask the failure message. Mirror the MCP bridge, which
+ // reads outputs only when the result is successful.
+ $outputs = $success ? $tool->getOutputValues() : [];
if ($options['json']) {
$result = [
```
issue