feat(cli): support compound tier-tool selectors (#1441)#1447
Conversation
Parse compound tier selectors when --tier value doesn't match a known tier. E.g. `--tier tier-4-critical-codex` → tier=tier-4-critical, tool=codex. Supports tool aliases (claude→claude-code, gemini→gemini-cli) and multi-segment tool names (claude-code). Applied across run, review, and debate commands. Extracted config tier helpers and review_cmd test barrel to stay under 800-line monolith gate. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request implements support for compound tier selectors in the format --tier <tier>-<tool>, enabling users to specify a tier and a tool override simultaneously. The implementation includes new parsing logic in run_helpers_compound_tier.rs, integration across the run, debate, and review commands, and a refactor of csa-config to support compound parsing. Review feedback highlights the need to use ToolArg::from_str for more robust alias resolution, the importance of including the original tier name in error contexts for better diagnostics, and a recommendation to persist pre-execution errors in the review command to ensure consistency with other CLI tools.
| fn resolve_alias_to_tool(alias_name: &str, cfg: &ProjectConfig) -> Option<ToolName> { | ||
| let canonical = cfg.tool_aliases.get(alias_name)?; | ||
| parse_tool_name(canonical).ok() | ||
| } |
There was a problem hiding this comment.
resolve_alias_to_tool uses parse_tool_name to resolve the canonical tool name from an alias. However, parse_tool_name only recognizes canonical tool strings (e.g., gemini-cli) and will fail for built-in aliases (e.g., gemini). This causes conflict detection to fail for user-defined aliases that point to built-in aliases. It should use ToolArg::from_str instead.
| fn resolve_alias_to_tool(alias_name: &str, cfg: &ProjectConfig) -> Option<ToolName> { | |
| let canonical = cfg.tool_aliases.get(alias_name)?; | |
| parse_tool_name(canonical).ok() | |
| } | |
| fn resolve_alias_to_tool(alias_name: &str, cfg: &ProjectConfig) -> Option<ToolName> { | |
| use std::str::FromStr; | |
| let canonical = cfg.tool_aliases.get(alias_name)?; | |
| match ToolArg::from_str(canonical).ok()? { | |
| ToolArg::Specific(t) => Some(t), | |
| _ => None, | |
| } | |
| } |
| parent: None, | ||
| tool_name: ctx.explicit_tool.map(|t| t.as_str()), | ||
| task_type: Some("debate"), | ||
| tier_name: None, |
| let parent_tool = crate::run_helpers::resolve_tool(detected_parent_tool, &global_config); | ||
| let effective_tier = resolve_review_effective_tier(&args, config.as_ref())?; | ||
| crate::run_helpers::warn_if_tier_without_tool(args.tier.as_deref(), args.tool.is_some()); | ||
| let (effective_tier, args_tool) = resolve_review_effective_tier(&args, config.as_ref())?; |
There was a problem hiding this comment.
Errors during effective tier resolution (including compound selector conflicts) should be persisted to the session directory to ensure consistent error reporting and observability, matching the pattern used in csa run and csa debate.
let (effective_tier, args_tool) = match resolve_review_effective_tier(&args, config.as_ref()) {
Ok(res) => res,
Err(err) => {
return Err(crate::session_guard::persist_pre_exec_error_result(
crate::session_guard::PreExecErrorCtx {
project_root: &project_root,
session_id: review_pre_exec_session_id(&args),
description: Some(review_description.as_str()),
parent: None,
tool_name: explicit_review_tool(&args).map(|tool| tool.as_str()),
task_type: Some("review"),
tier_name: args.tier.as_deref(),
error: err,
},
));
}
};
Summary
--tier tier-4-critical-codexas tier=tier-4-critical+ tool=codex, iterating hyphen splits from rightmost to handle multi-segment tool namestry_parse_compound_tier_tool,suggest_tier,format_tier_aliases) intoconfig_tier_helpers.rsto keep config.rs under 800 linesreview_cmd.rsintoreview_cmd_tests_barrel.rsto stay under monolith gate--toolstill winsTest plan
cargo test -p csa-config— tier selector tests passcargo test -p cli-sub-agent— review_cmd tests pass via barreljust pre-commit— all gates passCloses #1441
🤖 Generated with Claude Code