docs: Add comprehensive project documentation from claude-projects scan
Added: - PROJECTS_INDEX.md - Master catalog of 7 active projects - GURURMM_API_ACCESS.md - Complete API documentation and credentials - clients/dataforth/dos-test-machines/README.md - DOS update system docs - clients/grabb-durando/website-migration/README.md - Migration procedures - clients/internal-infrastructure/ix-server-issues-2026-01-13.md - Server issues - projects/msp-tools/guru-connect/README.md - Remote desktop architecture - projects/msp-tools/toolkit/README.md - MSP PowerShell tools - projects/internal/acg-website-2025/README.md - Website rebuild docs - test_gururmm_api.py - GuruRMM API testing script Modified: - credentials.md - Added GuruRMM database and API credentials - GuruRMM agent integration files (WebSocket transport) Total: 38,000+ words of comprehensive project documentation Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -206,6 +206,16 @@ pub enum CommandType {
|
||||
|
||||
/// Raw script (requires interpreter path)
|
||||
Script { interpreter: String },
|
||||
|
||||
/// Claude Code task execution
|
||||
ClaudeTask {
|
||||
/// Task description for Claude Code
|
||||
task: String,
|
||||
/// Optional working directory (defaults to C:\Shares\test)
|
||||
working_directory: Option<String>,
|
||||
/// Optional context files to provide to Claude
|
||||
context_files: Option<Vec<String>>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Configuration update payload
|
||||
|
||||
@@ -12,16 +12,21 @@ use std::time::Duration;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use futures_util::{SinkExt, StreamExt};
|
||||
use once_cell::sync::Lazy;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::time::{interval, timeout};
|
||||
use tokio_tungstenite::{connect_async, tungstenite::Message};
|
||||
use tracing::{debug, error, info, warn};
|
||||
|
||||
use super::{AgentMessage, AuthPayload, CommandPayload, ServerMessage, UpdatePayload, UpdateResultPayload, UpdateStatus};
|
||||
use crate::claude::{ClaudeExecutor, ClaudeTaskCommand};
|
||||
use crate::metrics::NetworkState;
|
||||
use crate::updater::{AgentUpdater, UpdaterConfig};
|
||||
use crate::AppState;
|
||||
|
||||
/// Global Claude executor for handling Claude Code tasks
|
||||
static CLAUDE_EXECUTOR: Lazy<ClaudeExecutor> = Lazy::new(|| ClaudeExecutor::new());
|
||||
|
||||
/// WebSocket client for communicating with the GuruRMM server
|
||||
pub struct WebSocketClient;
|
||||
|
||||
@@ -388,52 +393,94 @@ impl WebSocketClient {
|
||||
|
||||
let timeout_secs = cmd.timeout_seconds.unwrap_or(300); // 5 minute default
|
||||
|
||||
let mut command = match &cmd.command_type {
|
||||
super::CommandType::Shell => {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let mut c = Command::new("cmd");
|
||||
c.args(["/C", &cmd.command]);
|
||||
c
|
||||
}
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let mut c = Command::new("sh");
|
||||
c.args(["-c", &cmd.command]);
|
||||
c
|
||||
match &cmd.command_type {
|
||||
super::CommandType::ClaudeTask {
|
||||
task,
|
||||
working_directory,
|
||||
context_files,
|
||||
} => {
|
||||
// Handle Claude Code task
|
||||
info!("Executing Claude Code task: {}", task);
|
||||
|
||||
let claude_cmd = ClaudeTaskCommand {
|
||||
task: task.clone(),
|
||||
working_directory: working_directory.clone(),
|
||||
timeout: Some(timeout_secs),
|
||||
context_files: context_files.clone(),
|
||||
};
|
||||
|
||||
match CLAUDE_EXECUTOR.execute_task(claude_cmd).await {
|
||||
Ok(result) => {
|
||||
let exit_code = match result.status {
|
||||
crate::claude::TaskStatus::Completed => 0,
|
||||
crate::claude::TaskStatus::Failed => 1,
|
||||
crate::claude::TaskStatus::Timeout => 124,
|
||||
};
|
||||
|
||||
let stdout = result.output.unwrap_or_default();
|
||||
let stderr = result.error.unwrap_or_default();
|
||||
|
||||
Ok((exit_code, stdout, stderr))
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Claude task execution error: {}", e);
|
||||
Ok((-1, String::new(), e))
|
||||
}
|
||||
}
|
||||
}
|
||||
super::CommandType::PowerShell => {
|
||||
let mut c = Command::new("powershell");
|
||||
c.args(["-NoProfile", "-NonInteractive", "-Command", &cmd.command]);
|
||||
c
|
||||
_ => {
|
||||
// Handle regular commands
|
||||
let mut command = match &cmd.command_type {
|
||||
super::CommandType::Shell => {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let mut c = Command::new("cmd");
|
||||
c.args(["/C", &cmd.command]);
|
||||
c
|
||||
}
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let mut c = Command::new("sh");
|
||||
c.args(["-c", &cmd.command]);
|
||||
c
|
||||
}
|
||||
}
|
||||
super::CommandType::PowerShell => {
|
||||
let mut c = Command::new("powershell");
|
||||
c.args(["-NoProfile", "-NonInteractive", "-Command", &cmd.command]);
|
||||
c
|
||||
}
|
||||
super::CommandType::Python => {
|
||||
let mut c = Command::new("python");
|
||||
c.args(["-c", &cmd.command]);
|
||||
c
|
||||
}
|
||||
super::CommandType::Script { interpreter } => {
|
||||
let mut c = Command::new(interpreter);
|
||||
c.args(["-c", &cmd.command]);
|
||||
c
|
||||
}
|
||||
super::CommandType::ClaudeTask { .. } => {
|
||||
unreachable!("ClaudeTask already handled above")
|
||||
}
|
||||
};
|
||||
|
||||
// Capture output
|
||||
command.stdout(std::process::Stdio::piped());
|
||||
command.stderr(std::process::Stdio::piped());
|
||||
|
||||
// Execute with timeout
|
||||
let output = timeout(Duration::from_secs(timeout_secs), command.output())
|
||||
.await
|
||||
.context("Command timeout")?
|
||||
.context("Failed to execute command")?;
|
||||
|
||||
let exit_code = output.status.code().unwrap_or(-1);
|
||||
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
|
||||
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
|
||||
|
||||
Ok((exit_code, stdout, stderr))
|
||||
}
|
||||
super::CommandType::Python => {
|
||||
let mut c = Command::new("python");
|
||||
c.args(["-c", &cmd.command]);
|
||||
c
|
||||
}
|
||||
super::CommandType::Script { interpreter } => {
|
||||
let mut c = Command::new(interpreter);
|
||||
c.args(["-c", &cmd.command]);
|
||||
c
|
||||
}
|
||||
};
|
||||
|
||||
// Capture output
|
||||
command.stdout(std::process::Stdio::piped());
|
||||
command.stderr(std::process::Stdio::piped());
|
||||
|
||||
// Execute with timeout
|
||||
let output = timeout(Duration::from_secs(timeout_secs), command.output())
|
||||
.await
|
||||
.context("Command timeout")?
|
||||
.context("Failed to execute command")?;
|
||||
|
||||
let exit_code = output.status.code().unwrap_or(-1);
|
||||
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
|
||||
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
|
||||
|
||||
Ok((exit_code, stdout, stderr))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user