sync: Multi-project updates - SolverBot, GuruRMM, Dataforth
SolverBot: - Inject active project path into agent system prompts so agents know which directory to scope file operations to GuruRMM: - Bump agent version to 0.6.0 - Add serde aliases for PowerShell/ClaudeTask command types - Add typed CommandType enum on server for proper serialization - Support claude_task command type in send_command API Dataforth: - Fix SCP space-escaping in Sync-FromNAS.ps1 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,16 +10,16 @@ use uuid::Uuid;
|
||||
|
||||
use crate::auth::AuthUser;
|
||||
use crate::db::{self, Command};
|
||||
use crate::ws::{CommandPayload, ServerMessage};
|
||||
use crate::ws::{CommandPayload, CommandType, ServerMessage};
|
||||
use crate::AppState;
|
||||
|
||||
/// Request to send a command to an agent
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct SendCommandRequest {
|
||||
/// Command type (shell, powershell, python, script)
|
||||
/// Command type (shell, powershell, python, script, claude_task)
|
||||
pub command_type: String,
|
||||
|
||||
/// Command text to execute
|
||||
/// Command text to execute (also used as task description for claude_task)
|
||||
pub command: String,
|
||||
|
||||
/// Timeout in seconds (optional, default 300)
|
||||
@@ -27,6 +27,12 @@ pub struct SendCommandRequest {
|
||||
|
||||
/// Run as elevated/admin (optional, default false)
|
||||
pub elevated: Option<bool>,
|
||||
|
||||
/// Working directory for claude_task (optional, default C:\Shares\test)
|
||||
pub working_directory: Option<String>,
|
||||
|
||||
/// Context files for claude_task (optional)
|
||||
pub context_files: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
/// Response after sending a command
|
||||
@@ -59,6 +65,18 @@ pub async fn send_command(
|
||||
"Command sent by user"
|
||||
);
|
||||
|
||||
// Validate and build command type
|
||||
let command_type = if CommandType::is_claude_task(&req.command_type) {
|
||||
CommandType::new_claude_task(
|
||||
req.command.clone(),
|
||||
req.working_directory.clone(),
|
||||
req.context_files.clone(),
|
||||
)
|
||||
} else {
|
||||
CommandType::from_api_string(&req.command_type)
|
||||
.map_err(|e| (StatusCode::BAD_REQUEST, e))?
|
||||
};
|
||||
|
||||
// Verify agent exists
|
||||
let _agent = db::get_agent_by_id(&state.db, agent_id)
|
||||
.await
|
||||
@@ -66,9 +84,10 @@ pub async fn send_command(
|
||||
.ok_or((StatusCode::NOT_FOUND, "Agent not found".to_string()))?;
|
||||
|
||||
// Create command record with user ID for audit trail
|
||||
// Store the canonical db string format for consistency
|
||||
let create = db::CreateCommand {
|
||||
agent_id,
|
||||
command_type: req.command_type.clone(),
|
||||
command_type: command_type.as_db_string().to_string(),
|
||||
command_text: req.command.clone(),
|
||||
created_by: Some(user.user_id),
|
||||
};
|
||||
@@ -80,10 +99,11 @@ pub async fn send_command(
|
||||
// Check if agent is connected
|
||||
let agents = state.agents.read().await;
|
||||
if agents.is_connected(&agent_id) {
|
||||
// Send command via WebSocket
|
||||
// Send command via WebSocket using the proper enum type
|
||||
// This serializes as snake_case to match the agent's expected format
|
||||
let cmd_msg = ServerMessage::Command(CommandPayload {
|
||||
id: command.id,
|
||||
command_type: req.command_type,
|
||||
command_type,
|
||||
command: req.command,
|
||||
timeout_seconds: req.timeout_seconds,
|
||||
elevated: req.elevated.unwrap_or(false),
|
||||
|
||||
Reference in New Issue
Block a user