返回 CodeWhale
legacy.rs
根目录 / crates / tui / src / commands / groups / plugins / legacy.rs
1 //! Legacy executable plugin-tool inventory (`[tools].plugin_dir`).
2 //!
3 //! These are scripts, not declarative bundles: they are discovered by
4 //! scanning a directory, they carry their own approval requirement, and
5 //! they never share bundle trust state. `/plugin tools` reports them
6 //! read-only — nothing here installs, trusts, or executes anything.
7 //!
8 //! FEAT-020: this module consumes the portable `PluginLegacyScan` from the
9 //! plugin facet; no concrete `App` or `PluginMetadata` crosses the boundary.
10
11 use codewhale_command_contract::facets::{CommandPluginContext, CommandPresentationContext};
12 use std::fmt::Write as _;
13
14 use crate::commands::CommandResult;
15
16 pub(super) fn legacy_tools(
17 presentation: &mut dyn CommandPresentationContext,
18 plugin: &dyn CommandPluginContext,
19 name: Option<&str>,
20 ) -> CommandResult {
21 let scan = match plugin.legacy_scan() {
22 Ok(Some(scan)) => scan,
23 Ok(None) | Err(_) => {
24 return super::action_error(
25 presentation,
26 "Could not resolve the legacy executable plugin-tool directory",
27 );
28 }
29 };
30 match name {
31 Some(name) => show_legacy_tool_detail(presentation, name, &scan),
32 None => list_legacy_tools(presentation, &scan),
33 }
34 }
35
36 fn list_legacy_tools(
37 presentation: &mut dyn CommandPresentationContext,
38 scan: &codewhale_command_contract::facets::PluginLegacyScan,
39 ) -> CommandResult {
40 if scan.tools.is_empty() {
41 return CommandResult::message(
42 presentation
43 .translate(
44 "cmd_plugin_none_found",
45 &[("dir", &scan.dir.display().to_string())],
46 )
47 .unwrap_or_default(),
48 );
49 }
50 let mut output = presentation
51 .translate(
52 "cmd_plugin_legacy_list_header",
53 &[
54 ("count", &scan.tools.len().to_string()),
55 ("dir", &scan.dir.display().to_string()),
56 ],
57 )
58 .unwrap_or_default();
59 output.push('\n');
60 for tool in &scan.tools {
61 let _ = writeln!(
62 output,
63 "• {} — {}\n {}",
64 tool.name,
65 tool.description,
66 tool.path.display()
67 );
68 }
69 CommandResult::message(output)
70 }
71
72 fn show_legacy_tool_detail(
73 presentation: &mut dyn CommandPresentationContext,
74 name: &str,
75 scan: &codewhale_command_contract::facets::PluginLegacyScan,
76 ) -> CommandResult {
77 let Some(tool) = scan.tools.iter().find(|tool| tool.name == name) else {
78 return CommandResult::error(
79 presentation
80 .translate("cmd_plugin_not_found", &[("name", name)])
81 .unwrap_or_default(),
82 );
83 };
84 let schema = tool
85 .input_schema
86 .clone()
87 .unwrap_or_else(|| "{}".to_string());
88 let mut output = format!("{}\n{:=<40}\n", tool.name, "");
89 let _ = writeln!(
90 output,
91 "{}",
92 presentation
93 .translate(
94 "cmd_plugin_detail_description",
95 &[("description", &tool.description)],
96 )
97 .unwrap_or_default()
98 );
99 let _ = writeln!(
100 output,
101 "{}",
102 presentation
103 .translate("cmd_plugin_detail_schema", &[("schema", &schema)])
104 .unwrap_or_default()
105 );
106 let _ = writeln!(
107 output,
108 "{}",
109 presentation
110 .translate(
111 "cmd_plugin_detail_approval",
112 &[("approval", &tool.approval)]
113 )
114 .unwrap_or_default()
115 );
116 let _ = writeln!(
117 output,
118 "{}",
119 presentation
120 .translate(
121 "cmd_plugin_detail_path",
122 &[("path", &tool.path.display().to_string())]
123 )
124 .unwrap_or_default()
125 );
126 CommandResult::message(output)
127 }
128
128 lines RUST