1use clap::{Args, Parser, Subcommand};
2use clap_complete::Shell;
3
4use crate::output::OutputFormat;
5
6#[derive(Debug, Parser)]
7#[command(
8 name = "teams",
9 version,
10 long_version = env!("TEAMS_LONG_VERSION"),
11 about = "Microsoft Teams from your terminal, for humans and agents",
12 after_help = "Get started:\n teams init Guided setup\n teams tui --demo Explore without an account\n teams doctor Diagnose configuration and access\n teams schema --command 'messages send'\n Inspect the automation contract"
13)]
14pub struct Cli {
15 #[arg(long, global = true, env = "TEAMS_PROFILE")]
17 pub profile: Option<String>,
18 #[arg(short = 'o', long, global = true, value_enum, default_value = "auto")]
20 pub output: OutputFormat,
21 #[arg(long, global = true)]
23 pub quiet: bool,
24 #[arg(long, short = 'y', global = true)]
26 pub yes: bool,
27 #[arg(long, global = true, hide = true)]
29 pub json: bool,
30 #[command(subcommand)]
31 pub command: Option<Command>,
32}
33
34#[derive(Debug, Subcommand)]
35pub enum Command {
36 Init(InitArgs),
38 Auth {
40 #[command(subcommand)]
41 command: AuthCommand,
42 },
43 Profile {
45 #[command(subcommand)]
46 command: ProfileCommand,
47 },
48 Config {
50 #[command(subcommand)]
51 command: ConfigCommand,
52 },
53 Whoami,
55 List(OffsetPageArgs),
57 Channels {
59 #[command(subcommand)]
60 command: ChannelsCommand,
61 },
62 Chats {
64 #[command(subcommand)]
65 command: ChatsCommand,
66 },
67 Messages {
69 #[command(subcommand)]
70 command: MessagesCommand,
71 },
72 Tui(TuiArgs),
74 Doctor {
76 #[arg(long)]
78 offline: bool,
79 },
80 Desktop {
82 #[command(subcommand)]
83 command: DesktopCommand,
84 },
85 Capabilities,
87 Schema {
89 #[arg(long)]
90 command: Option<String>,
91 },
92 Completions { shell: Shell },
94 #[command(hide = true, name = "desktop-helper")]
96 DesktopHelper,
97}
98
99#[derive(Debug, Args)]
100pub struct InitArgs {
101 #[arg(long, value_enum, default_value = "graph")]
103 pub backend: crate::config::BackendKind,
104 #[arg(long, value_parser = clap::value_parser!(u16).range(1024..))]
106 pub desktop_port: Option<u16>,
107 #[arg(long, value_enum)]
109 pub desktop_account: Option<crate::config::DesktopAccount>,
110 #[arg(long)]
112 pub client_id: Option<String>,
113 #[arg(long)]
115 pub tenant: Option<String>,
116 #[arg(long)]
118 pub no_login: bool,
119 #[arg(long)]
121 pub device_code: bool,
122 #[arg(long)]
124 pub channel_history: bool,
125 #[arg(long, env = "TEAMS_READ_ONLY")]
127 pub read_only: bool,
128 #[arg(long)]
130 pub allow_send: bool,
131}
132
133#[derive(Debug, Subcommand)]
134pub enum ConfigCommand {
135 Show,
137 Path,
139}
140
141#[derive(Debug, Subcommand)]
142pub enum AuthCommand {
143 Login {
145 #[arg(long)]
147 device_code: bool,
148 #[arg(long)]
150 channel_history: bool,
151 },
152 Logout,
154 Status {
156 #[arg(long)]
158 offline: bool,
159 },
160}
161
162#[derive(Debug, Subcommand)]
163pub enum ProfileCommand {
164 List,
166 Use { name: String },
168 Remove { name: String },
170}
171
172#[derive(Debug, Subcommand)]
173pub enum ChannelsCommand {
174 List {
176 team: String,
177 #[command(flatten)]
178 page: OffsetPageArgs,
179 },
180}
181
182#[derive(Debug, Subcommand)]
183pub enum ChatsCommand {
184 List(PageArgs),
185}
186
187#[derive(Debug, Args, Clone)]
188pub struct PageArgs {
189 #[arg(long, default_value_t = 50, value_parser = clap::value_parser!(u16).range(1..=50))]
191 pub limit: u16,
192 #[arg(long)]
194 pub cursor: Option<String>,
195 #[arg(long)]
197 pub fields: Option<String>,
198}
199
200#[derive(Debug, Args, Clone)]
201pub struct OffsetPageArgs {
202 #[arg(long, default_value_t = 50, value_parser = clap::value_parser!(u16).range(1..=100))]
204 pub limit: u16,
205 #[arg(long, default_value_t = 0)]
207 pub offset: usize,
208 #[arg(long)]
210 pub fields: Option<String>,
211}
212
213#[derive(Debug, Subcommand)]
214pub enum MessagesCommand {
215 Status {
217 #[arg(long)]
218 chat: String,
219 #[arg(long)]
220 client_message_id: String,
221 },
222 List {
224 #[arg(long, conflicts_with = "team", required_unless_present = "team")]
225 chat: Option<String>,
226 #[arg(long, requires = "channel", required_unless_present = "chat")]
227 team: Option<String>,
228 #[arg(long, requires = "team")]
229 channel: Option<String>,
230 #[command(flatten)]
231 page: PageArgs,
232 },
233 Send {
235 #[arg(long, conflicts_with = "team", required_unless_present = "team")]
236 chat: Option<String>,
237 #[arg(long, requires = "channel", required_unless_present = "chat")]
238 team: Option<String>,
239 #[arg(long, requires = "team")]
240 channel: Option<String>,
241 #[arg(long)]
243 body: String,
244 },
245}
246
247#[derive(Debug, Args)]
248pub struct TuiArgs {
249 #[arg(long)]
251 pub demo: bool,
252 #[arg(long, requires = "demo")]
254 pub snapshot: bool,
255 #[arg(long, default_value_t = 100, hide = true)]
256 pub width: u16,
257 #[arg(long, default_value_t = 30, hide = true)]
258 pub height: u16,
259}
260
261#[derive(Debug, Subcommand)]
262pub enum DesktopCommand {
263 Status(DesktopArgs),
265 Connect(DesktopArgs),
267 Disconnect(DesktopArgs),
269 Recover(DesktopArgs),
271}
272
273#[derive(Debug, Args)]
274pub struct DesktopArgs {
275 #[arg(long, value_parser = clap::value_parser!(u16).range(1024..))]
277 pub port: Option<u16>,
278}