Skip to content

Commit c760a49

Browse files
committed
fix(#774): agents/plugins/mcp unknown-subcommand errors now include non-null hint
1 parent 727a1ea commit c760a49

2 files changed

Lines changed: 13 additions & 3 deletions

File tree

ROADMAP.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7713,3 +7713,5 @@ Original filing (2026-04-18): the session emitted `SessionStart hook (completed)
77137713
772. **Slash command aliases bypassed `bare_slash_command_guidance` lookup** — dogfooded 2026-05-27 on `bf212b98`. `bare_slash_command_guidance()` only checked `spec.name == command_name`, not `spec.aliases`, so `claw yes`, `claw no`, `claw y`, `claw n`, `claw skill`, `claw cwd` all fell through (either to typo suggestions or `missing_credentials`). Should have returned `interactive_only:` guidance referencing the canonical form. Fix: (1) lookup changed to `spec.name == command_name || spec.aliases.contains(&command_name)`; (2) capture `canonical_name = slash_command.name`; (3) guidance strings updated to reference canonical form in remediation (e.g., `claw yes → /approve`, `claw n → /deny`, `claw skill → /skills`). 36 CLI contract tests pass. [SCOPE: claw-code] Source: Gaebal-gajae pinpoint on `bf212b98`, 2026-05-27.
77147714

77157715
773. **Config deprecation warnings only emitted as unstructured stderr text in `--output-format json` mode** — dogfooded 2026-05-27 on `212f0b2a`. `emit_config_warning_once()` always wrote to stderr regardless of output format, causing JSON-mode callers to receive an unexpected `warning: ...` text line on stderr before the JSON object. Callers had to implement ad-hoc stripping. Fix: added `ConfigLoader::load_collecting_warnings()` method that returns `(RuntimeConfig, Vec<String>)` so callers can surface warnings structurally; `render_config_json()` now uses this and includes a `warnings: []` array in the config JSON envelope. Existing `load()` path unchanged (still emits to stderr for text-mode callers). 36 CLI contract tests pass. [SCOPE: claw-code] Source: Jobdori startup-friction probe on `212f0b2a`, 2026-05-27.
7716+
7717+
774. **`claw agents bogus`, `claw plugins bogus`, `claw mcp bogus` returned `hint: null`** — dogfooded 2026-05-27 on `727a1ea4`. Three "unknown subcommand" envelopes had `error_kind` correctly set but `hint: null`: (1) `unknown_agents_subcommand` — both text and JSON handler emitted single-line error with inline remediation after `.`, no `\n`; (2) `unknown_plugins_action` — same, period-delimited remediation; (3) `unknown_mcp_action` — `render_mcp_usage_json` never included a `hint` field at all. Fixes: (1)+(2) added `\n` before remediation suffix in `commands/src/lib.rs`; (3) added `hint` field to `render_mcp_usage_json` pointing at supported actions. All three now return non-null `hint`. 36 CLI contract tests pass. [SCOPE: claw-code] Source: Jobdori envelope-consistency probe on `727a1ea4`, 2026-05-27.

rust/crates/commands/src/lib.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2342,7 +2342,7 @@ pub fn handle_plugins_slash_command(
23422342
reload_runtime: false,
23432343
}),
23442344
Some(other) => Err(PluginError::CommandFailed(format!(
2345-
"unknown_plugins_action: '{other}' is not a supported /plugins action. Use list, show, install, enable, disable, uninstall, or update."
2345+
"unknown_plugins_action: '{other}' is not a supported /plugins action.\nUse: list, show, install, enable, disable, uninstall, or update."
23462346
))),
23472347
}
23482348
}
@@ -2406,7 +2406,7 @@ pub fn handle_agents_slash_command(args: Option<&str>, cwd: &Path) -> std::io::R
24062406
Some(args) if is_help_arg(args) => Ok(render_agents_usage(None)),
24072407
Some(args) => Err(std::io::Error::new(
24082408
std::io::ErrorKind::InvalidInput,
2409-
format!("unknown agents subcommand: {args}. Supported: list, show, help"),
2409+
format!("unknown agents subcommand: {args}.\nSupported: list, show, help"),
24102410
)),
24112411
}
24122412
}
@@ -2477,7 +2477,7 @@ pub fn handle_agents_slash_command_json(args: Option<&str>, cwd: &Path) -> std::
24772477
Some(args) if is_help_arg(args) => Ok(render_agents_usage_json(None)),
24782478
Some(args) => Err(std::io::Error::new(
24792479
std::io::ErrorKind::InvalidInput,
2480-
format!("unknown agents subcommand: {args}. Supported: list, show, help"),
2480+
format!("unknown agents subcommand: {args}.\nSupported: list, show, help"),
24812481
)),
24822482
}
24832483
}
@@ -4173,12 +4173,20 @@ fn render_mcp_usage_json(unexpected: Option<&str>) -> Value {
41734173
} else {
41744174
Value::Null
41754175
};
4176+
// #774: add hint field so unknown_mcp_action errors have non-null hint parity
4177+
// with agents/plugins unknown-subcommand envelopes.
4178+
let hint: Value = if unexpected.is_some() {
4179+
json!("Use: list, show <server>, or help")
4180+
} else {
4181+
Value::Null
4182+
};
41764183
json!({
41774184
"kind": "mcp",
41784185
"action": "help",
41794186
"ok": unexpected.is_none(),
41804187
"status": if unexpected.is_some() { "error" } else { "ok" },
41814188
"error_kind": error_kind,
4189+
"hint": hint,
41824190
"usage": {
41834191
"slash_command": "/mcp [list|show <server>|help]",
41844192
"direct_cli": "claw mcp [list|show <server>|help]",

0 commit comments

Comments
 (0)