1mod audit;
12mod cli;
13mod clipboard;
14mod doctor;
15mod env;
16mod helpers;
17mod init;
18mod input;
19mod ipc;
20mod launch;
21mod profile;
22mod secrets;
23mod snippets;
24mod ssh;
25mod status;
26mod unlock;
27mod wm;
28mod workspace;
29
30use clap::Parser;
31use owo_colors::OwoColorize;
32
33use cli::*;
34
35#[tokio::main(flavor = "current_thread")]
36async fn main() {
37 let cli = Cli::parse();
38
39 if let Err(e) = run(cli).await {
40 eprintln!("{}: {e:#}", "error".red().bold());
41 std::process::exit(1);
42 }
43}
44
45async fn run(cli: Cli) -> anyhow::Result<()> {
46 match cli.command {
47 Command::Init {
48 no_keybinding,
49 wipe_reset_destroy_all_data,
50 org,
51 ssh_key,
52 password,
53 auth_policy,
54 } => {
55 if wipe_reset_destroy_all_data {
56 init::cmd_wipe()
57 } else {
58 init::cmd_init(no_keybinding, org, ssh_key, password, auth_policy).await
59 }
60 }
61 Command::Status {
62 doctor,
63 output,
64 exit_code,
65 quiet,
66 rotate_keys,
67 } => {
68 if rotate_keys {
69 use owo_colors::OwoColorize;
70 let client = ipc::connect().await?;
71 match ipc::rpc(
72 &client,
73 core_types::EventKind::KeyRotationRequest,
74 core_types::SecurityLevel::Internal,
75 )
76 .await?
77 {
78 core_types::EventKind::KeyRotationRequestResponse { success: true, .. } => {
79 println!(
80 "{} Key rotation initiated. Phase 2 completes in 30 seconds.",
81 "✓".green().bold()
82 );
83 Ok(())
84 }
85 core_types::EventKind::KeyRotationRequestResponse {
86 success: false,
87 error,
88 } => {
89 let reason = error.as_deref().unwrap_or("unknown");
90 anyhow::bail!("key rotation failed: {reason}");
91 }
92 other => anyhow::bail!("unexpected response: {other:?}"),
93 }
94 } else if let Some(categories) = doctor {
95 doctor::cmd_doctor(
96 &categories,
97 output.as_deref().unwrap_or("text"),
98 exit_code || quiet,
99 quiet,
100 )
101 } else {
102 status::cmd_status().await
103 }
104 }
105 Command::Unlock { profile } => unlock::cmd_unlock(profile).await,
106 Command::Lock { profile } => unlock::cmd_lock(profile).await,
107 Command::Profile(sub) => match sub {
108 ProfileCmd::List => profile::cmd_profile_list().await,
109 ProfileCmd::Activate { name } => profile::cmd_profile_activate(&name).await,
110 ProfileCmd::Deactivate { name } => profile::cmd_profile_deactivate(&name).await,
111 ProfileCmd::Default { name } => profile::cmd_profile_default(&name).await,
112 ProfileCmd::Show { name } => profile::cmd_profile_show(&name),
113 },
114 Command::Ssh(sub) => match sub {
115 SshCmd::Enroll { profile, ssh_key } => ssh::cmd_ssh_enroll(profile, ssh_key).await,
116 SshCmd::List { profile } => ssh::cmd_ssh_list(profile).await,
117 SshCmd::Revoke { profile } => ssh::cmd_ssh_revoke(profile).await,
118 },
119 Command::Secret(sub) => match sub {
120 SecretCmd::Set { profile, key } => secrets::cmd_secret_set(&profile, &key).await,
121 SecretCmd::Get { profile, key } => secrets::cmd_secret_get(&profile, &key).await,
122 SecretCmd::Delete { profile, key, yes } => {
123 secrets::cmd_secret_delete(&profile, &key, yes).await
124 }
125 SecretCmd::List { profile } => secrets::cmd_secret_list(&profile).await,
126 },
127 Command::Audit(sub) => match sub {
128 AuditCmd::Verify => audit::cmd_audit_verify(),
129 AuditCmd::Tail { count, follow } => audit::cmd_audit_tail(count, follow).await,
130 },
131 Command::Wm(sub) => match sub {
132 WmCmd::List => wm::cmd_wm_list().await,
133 WmCmd::Switch { backward } => wm::cmd_wm_switch(backward).await,
134 WmCmd::Focus { window_id } => wm::cmd_wm_focus(&window_id).await,
135 WmCmd::Overlay { launcher, backward } => wm::cmd_wm_overlay(launcher, backward).await,
136 WmCmd::OverlayResident => wm::cmd_wm_overlay_resident().await,
137 },
138 Command::Launch(sub) => match sub {
139 LaunchCmd::Search {
140 query,
141 max_results,
142 profile,
143 } => launch::cmd_launch_search(&query, max_results, profile.as_deref()).await,
144 LaunchCmd::Run { entry_id, profile } => {
145 launch::cmd_launch_run(&entry_id, profile.as_deref()).await
146 }
147 },
148 Command::Clipboard(sub) => match sub {
149 ClipboardCmd::History { profile, limit } => {
150 clipboard::cmd_clipboard_history(&profile, limit).await
151 }
152 ClipboardCmd::Clear { profile } => clipboard::cmd_clipboard_clear(&profile).await,
153 ClipboardCmd::Get { entry_id } => clipboard::cmd_clipboard_get(&entry_id).await,
154 },
155 Command::Input(sub) => match sub {
156 InputCmd::Layers => input::cmd_input_layers().await,
157 InputCmd::Status => input::cmd_input_status().await,
158 },
159 Command::Snippet(sub) => match sub {
160 SnippetCmd::List { profile } => snippets::cmd_snippet_list(&profile).await,
161 SnippetCmd::Expand { profile, trigger } => {
162 snippets::cmd_snippet_expand(&profile, &trigger).await
163 }
164 SnippetCmd::Add {
165 profile,
166 trigger,
167 template,
168 } => snippets::cmd_snippet_add(&profile, &trigger, &template).await,
169 },
170 #[cfg(all(target_os = "linux", feature = "desktop"))]
171 Command::SetupKeybinding { launcher_key } => {
172 platform_linux::cosmic_keys::setup_keybinding(&launcher_key)
173 .map_err(|e| anyhow::anyhow!("{e}"))
174 }
175 #[cfg(all(target_os = "linux", feature = "desktop"))]
176 Command::RemoveKeybinding => {
177 platform_linux::cosmic_keys::remove_keybinding().map_err(|e| anyhow::anyhow!("{e}"))
178 }
179 #[cfg(all(target_os = "linux", feature = "desktop"))]
180 Command::KeybindingStatus => {
181 platform_linux::cosmic_keys::keybinding_status().map_err(|e| anyhow::anyhow!("{e}"))
182 }
183 Command::Clone {
184 url,
185 depth,
186 profile,
187 no_workspace,
188 project,
189 include_forks,
190 include_archived,
191 } => {
192 workspace::cmd_workspace(WorkspaceCmd::Clone {
194 url,
195 depth,
196 profile,
197 adopt: true,
198 workspace_init: false,
199 workspace_update: false,
200 no_workspace,
201 force: false,
202 project,
203 include_forks,
204 include_archived,
205 })
206 .await
207 }
208 Command::Env {
209 profile,
210 prefix,
211 command,
212 } => env::cmd_env(profile.as_deref(), prefix.as_deref(), &command).await,
213 Command::Export {
214 profile,
215 format,
216 prefix,
217 } => env::cmd_export(profile.as_deref(), &format, prefix.as_deref()).await,
218 Command::Workspace(sub) => workspace::cmd_workspace(sub).await,
219 }
220}