1pub mod args;
8pub mod bake;
9pub mod dispatch;
10pub mod dynamic;
11pub mod list;
12
13pub use dispatch::dispatch;
14
15use std::collections::HashSet;
16use std::ffi::OsString;
17
18pub fn split_at_subcommand(
23 argv: &[OsString],
24 value_options: &HashSet<String>,
25 bool_options: &HashSet<String>,
26) -> (Vec<OsString>, Vec<OsString>) {
27 let _ = bool_options; let mut i = 0;
29 while i < argv.len() {
30 let arg = argv[i].to_string_lossy();
31 if arg == "--" {
32 return (argv[..i].to_vec(), argv[i + 1..].to_vec());
33 }
34 if arg.starts_with('-') {
35 if arg.starts_with("--") && arg.contains('=') {
36 i += 1;
37 } else if value_options.contains(arg.as_ref()) {
38 i += 2;
39 } else {
40 i += 1;
42 }
43 } else {
44 return (argv[..i].to_vec(), argv[i..].to_vec());
45 }
46 }
47 (argv.to_vec(), Vec::new())
48}
49
50pub fn global_option_sets() -> (HashSet<String>, HashSet<String>) {
52 let value = [
53 "--spec",
54 "--mcp",
55 "--mcp-stdio",
56 "--graphql",
57 "--auth-header",
58 "--base-url",
59 "--cache-key",
60 "--cache-ttl",
61 "--search",
62 "--sort",
63 "--top",
64 "--head",
65 "--detail",
66 "--describe",
67 "--max-bytes",
68 "--fields",
69 "--transport",
70 "--env",
71 "--oauth-client-id",
72 "--oauth-client-secret",
73 "--oauth-client-name",
74 "--oauth-scope",
75 "--oauth-redirect-uri",
76 "--oauth-flow",
77 "--read-resource",
78 "--get-prompt",
79 "--prompt-arg",
80 "--session-start",
81 "--session-stop",
82 "--session",
83 "--session-idle-secs",
84 ]
85 .into_iter()
86 .map(str::to_string)
87 .collect();
88
89 let bools = [
90 "--refresh",
91 "--list",
92 "--verbose",
93 "--compact",
94 "--pretty",
95 "--raw",
96 "--json",
97 "--toon",
98 "--envelope",
99 "--full",
100 "--inline",
101 "--agent",
102 "--spool-clean",
103 "--oauth",
104 "--oauth-clear",
105 "--list-resources",
106 "--list-resource-templates",
107 "--list-prompts",
108 "--session-list",
109 "--session-clean-env",
110 "--version",
111 "-V",
112 "-h",
113 "--help",
114 ]
115 .into_iter()
116 .map(str::to_string)
117 .collect();
118
119 (value, bools)
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 fn os(s: &str) -> OsString {
127 OsString::from(s)
128 }
129
130 #[test]
131 fn splits_before_subcommand() {
132 let (value, bools) = global_option_sets();
133 let argv = vec![
134 os("--mcp"),
135 os("http://example.com"),
136 os("--list"),
137 os("search"),
138 os("--query"),
139 os("hi"),
140 ];
141 let (global, tool) = split_at_subcommand(&argv, &value, &bools);
142 assert_eq!(
143 global,
144 vec![os("--mcp"), os("http://example.com"), os("--list")]
145 );
146 assert_eq!(tool, vec![os("search"), os("--query"), os("hi")]);
147 }
148
149 #[test]
150 fn double_dash_separator() {
151 let (value, bools) = global_option_sets();
152 let argv = vec![os("--spec"), os("a.json"), os("--"), os("--env"), os("x=1")];
153 let (global, tool) = split_at_subcommand(&argv, &value, &bools);
154 assert_eq!(global, vec![os("--spec"), os("a.json")]);
155 assert_eq!(tool, vec![os("--env"), os("x=1")]);
156 }
157}