Add machine deletion API with uninstall command support

- Add AdminCommand message to protobuf (uninstall, restart, update)
- Add DELETE /api/machines/:agent_id endpoint with options:
  - ?uninstall=true - send uninstall command to online agent
  - ?export=true - return session history before deletion
- Add GET /api/machines/:agent_id/history endpoint for history export
- Add GET /api/machines endpoint to list all machines
- Handle AdminCommand in agent session handler
- Handle ADMIN_UNINSTALL error in agent main loop to trigger uninstall

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
AZ Computer Guru
2025-12-29 19:15:16 -07:00
parent 05ab8a8bf4
commit dc7b7427ce
8 changed files with 380 additions and 6 deletions

View File

@@ -416,7 +416,21 @@ async fn run_agent(config: config::Config) -> Result<()> {
return Ok(());
}
error!("Session error: {}", e);
if error_msg.contains("ADMIN_UNINSTALL") {
info!("Uninstall command received from server - uninstalling");
if let Err(e) = startup::uninstall() {
warn!("Uninstall failed: {}", e);
}
show_message_box("GuruConnect Removed", "This computer has been removed from remote management.");
return Ok(());
}
if error_msg.contains("ADMIN_RESTART") {
info!("Restart command received - will reconnect");
// Don't exit, just let the loop continue to reconnect
} else {
error!("Session error: {}", e);
}
}
}
Err(e) => {

View File

@@ -452,6 +452,30 @@ impl SessionManager {
}
}
Some(message::Payload::AdminCommand(cmd)) => {
use crate::proto::AdminCommandType;
tracing::info!("Admin command received: {:?} - {}", cmd.command, cmd.reason);
match AdminCommandType::try_from(cmd.command).ok() {
Some(AdminCommandType::AdminUninstall) => {
tracing::warn!("Uninstall command received from server");
// Return special error to trigger uninstall in main loop
return Err(anyhow::anyhow!("ADMIN_UNINSTALL: {}", cmd.reason));
}
Some(AdminCommandType::AdminRestart) => {
tracing::info!("Restart command received from server");
// For now, just disconnect - the auto-restart logic will handle it
return Err(anyhow::anyhow!("ADMIN_RESTART: {}", cmd.reason));
}
Some(AdminCommandType::AdminUpdate) => {
tracing::info!("Update command received (not implemented)");
}
None => {
tracing::warn!("Unknown admin command: {}", cmd.command);
}
}
}
Some(message::Payload::Disconnect(disc)) => {
tracing::info!("Disconnect requested: {}", disc.reason);
if disc.reason.contains("cancelled") {