summaryrefslogblamecommitdiff
path: root/makima/src/daemon/api/supervisor.rs
blob: b691cc4628c5de47d64f594b74c9be046b15d0a9 (plain) (tree)

























































































































































































                                                                                                
//! Supervisor API methods.

use serde::{Deserialize, Serialize};
use uuid::Uuid;

use super::client::{ApiClient, ApiError};

// Request/Response types

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SpawnTaskRequest {
    pub name: String,
    pub plan: String,
    pub contract_id: Uuid,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub parent_task_id: Option<Uuid>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub checkpoint_sha: Option<String>,
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct WaitRequest {
    pub timeout_seconds: i32,
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ReadFileRequest {
    pub file_path: String,
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateBranchRequest {
    pub branch_name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub from_ref: Option<String>,
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct MergeRequest {
    pub squash: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub target_branch: Option<String>,
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CreatePrRequest {
    pub task_id: Uuid,
    pub title: String,
    pub body: String,
    pub base_branch: String,
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CheckpointRequest {
    pub message: String,
}

// Generic response type for JSON output
#[derive(Deserialize, Serialize)]
pub struct JsonValue(pub serde_json::Value);

impl ApiClient {
    /// Get all tasks in a contract.
    pub async fn supervisor_tasks(&self, contract_id: Uuid) -> Result<JsonValue, ApiError> {
        self.get(&format!("/api/v1/mesh/supervisor/contracts/{}/tasks", contract_id))
            .await
    }

    /// Get task tree structure.
    pub async fn supervisor_tree(&self, contract_id: Uuid) -> Result<JsonValue, ApiError> {
        self.get(&format!("/api/v1/mesh/supervisor/contracts/{}/tree", contract_id))
            .await
    }

    /// Spawn a new task.
    pub async fn supervisor_spawn(&self, req: SpawnTaskRequest) -> Result<JsonValue, ApiError> {
        self.post("/api/v1/mesh/supervisor/tasks", &req).await
    }

    /// Wait for a task to complete.
    pub async fn supervisor_wait(
        &self,
        task_id: Uuid,
        timeout_seconds: i32,
    ) -> Result<JsonValue, ApiError> {
        let req = WaitRequest { timeout_seconds };
        self.post(&format!("/api/v1/mesh/supervisor/tasks/{}/wait", task_id), &req)
            .await
    }

    /// Read a file from a task's worktree.
    pub async fn supervisor_read_file(
        &self,
        task_id: Uuid,
        file_path: &str,
    ) -> Result<JsonValue, ApiError> {
        let req = ReadFileRequest {
            file_path: file_path.to_string(),
        };
        self.post(&format!("/api/v1/mesh/supervisor/tasks/{}/read-file", task_id), &req)
            .await
    }

    /// Create a new branch.
    pub async fn supervisor_branch(
        &self,
        branch_name: &str,
        from_ref: Option<String>,
    ) -> Result<JsonValue, ApiError> {
        let req = CreateBranchRequest {
            branch_name: branch_name.to_string(),
            from_ref,
        };
        self.post("/api/v1/mesh/supervisor/branches", &req).await
    }

    /// Merge a task's changes.
    pub async fn supervisor_merge(
        &self,
        task_id: Uuid,
        target_branch: Option<String>,
        squash: bool,
    ) -> Result<JsonValue, ApiError> {
        let req = MergeRequest {
            squash,
            target_branch,
        };
        self.post(&format!("/api/v1/mesh/supervisor/tasks/{}/merge", task_id), &req)
            .await
    }

    /// Create a pull request.
    pub async fn supervisor_pr(
        &self,
        task_id: Uuid,
        title: &str,
        body: &str,
        base_branch: &str,
    ) -> Result<JsonValue, ApiError> {
        let req = CreatePrRequest {
            task_id,
            title: title.to_string(),
            body: body.to_string(),
            base_branch: base_branch.to_string(),
        };
        self.post("/api/v1/mesh/supervisor/pr", &req).await
    }

    /// Get task diff.
    pub async fn supervisor_diff(&self, task_id: Uuid) -> Result<JsonValue, ApiError> {
        self.get(&format!("/api/v1/mesh/supervisor/tasks/{}/diff", task_id))
            .await
    }

    /// Create a checkpoint.
    pub async fn supervisor_checkpoint(
        &self,
        task_id: Uuid,
        message: &str,
    ) -> Result<JsonValue, ApiError> {
        let req = CheckpointRequest {
            message: message.to_string(),
        };
        self.post(&format!("/api/v1/mesh/tasks/{}/checkpoint", task_id), &req)
            .await
    }

    /// List checkpoints.
    pub async fn supervisor_checkpoints(&self, task_id: Uuid) -> Result<JsonValue, ApiError> {
        self.get(&format!("/api/v1/mesh/tasks/{}/checkpoints", task_id))
            .await
    }

    /// Get contract status.
    pub async fn supervisor_status(&self, contract_id: Uuid) -> Result<JsonValue, ApiError> {
        self.get(&format!("/api/v1/contracts/{}/daemon/status", contract_id))
            .await
    }
}