ai_agent/commands/
plugin_parse_args.rs1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6#[serde(tag = "type")]
7pub enum ParsedCommand {
8 #[serde(rename = "menu")]
9 Menu,
10 #[serde(rename = "help")]
11 Help,
12 #[serde(rename = "install")]
13 Install {
14 #[serde(skip_serializing_if = "Option::is_none")]
15 marketplace: Option<String>,
16 #[serde(skip_serializing_if = "Option::is_none")]
17 plugin: Option<String>,
18 },
19 #[serde(rename = "manage")]
20 Manage,
21 #[serde(rename = "uninstall")]
22 Uninstall {
23 #[serde(skip_serializing_if = "Option::is_none")]
24 plugin: Option<String>,
25 },
26 #[serde(rename = "enable")]
27 Enable {
28 #[serde(skip_serializing_if = "Option::is_none")]
29 plugin: Option<String>,
30 },
31 #[serde(rename = "disable")]
32 Disable {
33 #[serde(skip_serializing_if = "Option::is_none")]
34 plugin: Option<String>,
35 },
36 #[serde(rename = "validate")]
37 Validate {
38 #[serde(skip_serializing_if = "Option::is_none")]
39 path: Option<String>,
40 },
41 #[serde(rename = "marketplace")]
42 Marketplace {
43 #[serde(skip_serializing_if = "Option::is_none")]
44 action: Option<String>,
45 #[serde(skip_serializing_if = "Option::is_none")]
46 target: Option<String>,
47 },
48}
49
50pub fn parse_plugin_args(args: Option<&str>) -> ParsedCommand {
51 let args = match args {
52 Some(a) => a.trim(),
53 None => "",
54 };
55 if args.is_empty() {
56 return ParsedCommand::Menu;
57 }
58
59 let parts: Vec<&str> = args.split_whitespace().collect();
60 let command = parts.first().map(|s| s.to_lowercase());
61
62 match command.as_deref() {
63 Some("help") | Some("--help") | Some("-h") => ParsedCommand::Help,
64
65 Some("install") | Some("i") => {
66 let target = parts.get(1).map(|s| s.to_string());
67
68 if let Some(t) = target {
69 if t.contains('@') {
71 let parts: Vec<&str> = t.split('@').collect();
72 if parts.len() == 2 {
73 return ParsedCommand::Install {
74 plugin: Some(parts[0].to_string()),
75 marketplace: Some(parts[1].to_string()),
76 };
77 }
78 }
79
80 let is_marketplace = t.starts_with("http://")
82 || t.starts_with("https://")
83 || t.starts_with("file://")
84 || t.contains('/')
85 || t.contains('\\');
86
87 if is_marketplace {
88 return ParsedCommand::Install {
89 marketplace: Some(t),
90 plugin: None,
91 };
92 }
93
94 return ParsedCommand::Install {
96 plugin: Some(t),
97 marketplace: None,
98 };
99 }
100
101 ParsedCommand::Install {
102 marketplace: None,
103 plugin: None,
104 }
105 }
106
107 Some("manage") => ParsedCommand::Manage,
108
109 Some("uninstall") => ParsedCommand::Uninstall {
110 plugin: parts.get(1).map(|s| s.to_string()),
111 },
112
113 Some("enable") => ParsedCommand::Enable {
114 plugin: parts.get(1).map(|s| s.to_string()),
115 },
116
117 Some("disable") => ParsedCommand::Disable {
118 plugin: parts.get(1).map(|s| s.to_string()),
119 },
120
121 Some("validate") => {
122 let target = parts[1..].join(" ").trim().to_string();
123 ParsedCommand::Validate {
124 path: if target.is_empty() {
125 None
126 } else {
127 Some(target)
128 },
129 }
130 }
131
132 Some("marketplace") | Some("market") => {
133 let action = parts.get(1).map(|s| s.to_lowercase());
134 let target = parts[2..].join(" ");
135
136 match action.as_deref() {
137 Some("add") => ParsedCommand::Marketplace {
138 action: Some("add".to_string()),
139 target: if target.is_empty() {
140 None
141 } else {
142 Some(target)
143 },
144 },
145 Some("remove") | Some("rm") => ParsedCommand::Marketplace {
146 action: Some("remove".to_string()),
147 target: if target.is_empty() {
148 None
149 } else {
150 Some(target)
151 },
152 },
153 Some("update") => ParsedCommand::Marketplace {
154 action: Some("update".to_string()),
155 target: if target.is_empty() {
156 None
157 } else {
158 Some(target)
159 },
160 },
161 Some("list") => ParsedCommand::Marketplace {
162 action: Some("list".to_string()),
163 target: None,
164 },
165 _ => ParsedCommand::Marketplace {
166 action: None,
167 target: None,
168 },
169 }
170 }
171
172 _ => ParsedCommand::Menu,
174 }
175}