Entry point for `tracedecay tool ...`.
(
project: Option<String>,
name: Option<String>,
args: Vec<String>,
)
| 84 | |
| 85 | /// Entry point for `tracedecay tool ...`. |
| 86 | pub(crate) async fn run( |
| 87 | project: Option<String>, |
| 88 | name: Option<String>, |
| 89 | args: Vec<String>, |
| 90 | ) -> Result<()> { |
| 91 | let defs = get_tool_definitions(); |
| 92 | |
| 93 | let Some(raw_name) = name else { |
| 94 | print_tool_list(&defs); |
| 95 | return Ok(()); |
| 96 | }; |
| 97 | |
| 98 | let canonical = canonical_tool_name(&raw_name); |
| 99 | let Some(def) = defs.iter().find(|d| d.name == canonical) else { |
| 100 | let suggestion = nearest_tool_name(&canonical, &defs) |
| 101 | .map(|name| format!(" Did you mean '{name}'?")) |
| 102 | .unwrap_or_default(); |
| 103 | return Err(TraceDecayError::Config { |
| 104 | message: format!( |
| 105 | "unknown tool: '{raw_name}'.{suggestion} Run `tracedecay tool` to list available tools." |
| 106 | ), |
| 107 | }); |
| 108 | }; |
| 109 | |
| 110 | let parsed = parse_invocation(def, &args)?; |
| 111 | if parsed.show_help { |
| 112 | print_tool_help(def); |
| 113 | return Ok(()); |
| 114 | } |
| 115 | let ParsedInvocation { |
| 116 | tool_args, |
| 117 | project: parsed_project, |
| 118 | raw_json, |
| 119 | dry_run, |
| 120 | show_help: _, |
| 121 | } = parsed; |
| 122 | |
| 123 | if dry_run { |
| 124 | println!( |
| 125 | "{}", |
| 126 | serde_json::to_string_pretty(&tool_args).unwrap_or_default() |
| 127 | ); |
| 128 | return Ok(()); |
| 129 | } |
| 130 | |
| 131 | if is_profile_scoped_lcm_dispatch(&def.name, &tool_args) { |
| 132 | return dispatch_daemon_tool( |
| 133 | DaemonToolDispatch::profile_scoped(), |
| 134 | &def.name, |
| 135 | tool_args, |
| 136 | raw_json, |
| 137 | ) |
| 138 | .await; |
| 139 | } |
| 140 | |
| 141 | let explicit_project = project.or(parsed_project); |
| 142 | dispatch_daemon_tool( |
| 143 | DaemonToolDispatch::project_scoped(explicit_project, &def.name), |
nothing calls this directly
no test coverage detected