//! Directive API methods. use uuid::Uuid; use super::client::{ApiClient, ApiError}; use super::supervisor::JsonValue; impl ApiClient { /// Create a new directive. pub async fn create_directive( &self, goal: &str, repository_url: Option<&str>, autonomy_level: &str, ) -> Result { #[derive(serde::Serialize)] #[serde(rename_all = "camelCase")] struct CreateRequest<'a> { goal: &'a str, repository_url: Option<&'a str>, autonomy_level: &'a str, } let req = CreateRequest { goal, repository_url, autonomy_level, }; self.post("/api/v1/directives", &req).await } /// List all directives for the authenticated user. pub async fn list_directives( &self, status: Option<&str>, limit: i32, ) -> Result { let mut params = Vec::new(); if let Some(s) = status { params.push(format!("status={}", s)); } params.push(format!("limit={}", limit)); let query_string = format!("?{}", params.join("&")); self.get(&format!("/api/v1/directives{}", query_string)) .await } /// Get a directive by ID (includes progress info). pub async fn get_directive(&self, directive_id: Uuid) -> Result { self.get(&format!("/api/v1/directives/{}", directive_id)) .await } /// Archive a directive. pub async fn archive_directive(&self, directive_id: Uuid) -> Result { self.delete_with_response(&format!("/api/v1/directives/{}", directive_id)) .await } /// Start a directive (plans and begins execution). pub async fn start_directive(&self, directive_id: Uuid) -> Result { self.post_empty(&format!("/api/v1/directives/{}/start", directive_id)) .await } /// Pause a directive. pub async fn pause_directive(&self, directive_id: Uuid) -> Result { self.post_empty(&format!("/api/v1/directives/{}/pause", directive_id)) .await } /// Resume a paused directive. pub async fn resume_directive(&self, directive_id: Uuid) -> Result { self.post_empty(&format!("/api/v1/directives/{}/resume", directive_id)) .await } /// Stop a directive. pub async fn stop_directive(&self, directive_id: Uuid) -> Result { self.post_empty(&format!("/api/v1/directives/{}/stop", directive_id)) .await } /// Get the current chain and steps for a directive. pub async fn get_directive_chain(&self, directive_id: Uuid) -> Result { self.get(&format!("/api/v1/directives/{}/chain", directive_id)) .await } /// Get directive DAG structure for visualization. pub async fn get_directive_graph(&self, directive_id: Uuid) -> Result { self.get(&format!("/api/v1/directives/{}/chain/graph", directive_id)) .await } /// List events for a directive. pub async fn list_directive_events( &self, directive_id: Uuid, limit: i32, ) -> Result { self.get(&format!( "/api/v1/directives/{}/events?limit={}", directive_id, limit )) .await } /// List pending approvals for a directive. pub async fn list_directive_approvals( &self, directive_id: Uuid, ) -> Result { self.get(&format!("/api/v1/directives/{}/approvals", directive_id)) .await } /// Approve an approval request. pub async fn approve_directive_request( &self, directive_id: Uuid, approval_id: Uuid, response: Option<&str>, ) -> Result { #[derive(serde::Serialize)] #[serde(rename_all = "camelCase")] struct ApprovalRequest<'a> { response: Option<&'a str>, } let req = ApprovalRequest { response }; self.post( &format!( "/api/v1/directives/{}/approvals/{}/approve", directive_id, approval_id ), &req, ) .await } /// Deny an approval request. pub async fn deny_directive_request( &self, directive_id: Uuid, approval_id: Uuid, response: Option<&str>, ) -> Result { #[derive(serde::Serialize)] #[serde(rename_all = "camelCase")] struct ApprovalRequest<'a> { response: Option<&'a str>, } let req = ApprovalRequest { response }; self.post( &format!( "/api/v1/directives/{}/approvals/{}/deny", directive_id, approval_id ), &req, ) .await } // ========================================================================= // Chain operations // ========================================================================= /// Force chain regeneration (replan). pub async fn replan_directive_chain( &self, directive_id: Uuid, ) -> Result { self.post_empty(&format!( "/api/v1/directives/{}/chain/replan", directive_id )) .await } // ========================================================================= // Step management // ========================================================================= /// Add a step to a directive's chain. pub async fn add_directive_step( &self, directive_id: Uuid, name: &str, description: Option<&str>, step_type: Option<&str>, depends_on: Option>, ) -> Result { #[derive(serde::Serialize)] #[serde(rename_all = "camelCase")] struct AddStepReq<'a> { name: &'a str, #[serde(skip_serializing_if = "Option::is_none")] description: Option<&'a str>, #[serde(skip_serializing_if = "Option::is_none")] step_type: Option<&'a str>, #[serde(skip_serializing_if = "Option::is_none")] depends_on: Option>, } let req = AddStepReq { name, description, step_type, depends_on, }; self.post( &format!("/api/v1/directives/{}/chain/steps", directive_id), &req, ) .await } /// Get a step by ID. pub async fn get_directive_step( &self, directive_id: Uuid, step_id: Uuid, ) -> Result { self.get(&format!( "/api/v1/directives/{}/chain/steps/{}", directive_id, step_id )) .await } /// Update a step. pub async fn update_directive_step( &self, directive_id: Uuid, step_id: Uuid, update: serde_json::Value, ) -> Result { self.put( &format!( "/api/v1/directives/{}/chain/steps/{}", directive_id, step_id ), &update, ) .await } /// Delete a step. pub async fn delete_directive_step( &self, directive_id: Uuid, step_id: Uuid, ) -> Result<(), ApiError> { self.delete(&format!( "/api/v1/directives/{}/chain/steps/{}", directive_id, step_id )) .await } /// Skip a step. pub async fn skip_directive_step( &self, directive_id: Uuid, step_id: Uuid, ) -> Result { self.post_empty(&format!( "/api/v1/directives/{}/chain/steps/{}/skip", directive_id, step_id )) .await } /// Force re-evaluation of a step. pub async fn evaluate_directive_step( &self, directive_id: Uuid, step_id: Uuid, ) -> Result { self.post_empty(&format!( "/api/v1/directives/{}/chain/steps/{}/evaluate", directive_id, step_id )) .await } /// Trigger manual rework for a step. pub async fn rework_directive_step( &self, directive_id: Uuid, step_id: Uuid, instructions: Option<&str>, ) -> Result { #[derive(serde::Serialize)] #[serde(rename_all = "camelCase")] struct ReworkReq<'a> { instructions: Option<&'a str>, } let req = ReworkReq { instructions }; self.post( &format!( "/api/v1/directives/{}/chain/steps/{}/rework", directive_id, step_id ), &req, ) .await } // ========================================================================= // Evaluations // ========================================================================= /// List evaluations for a directive. pub async fn list_directive_evaluations( &self, directive_id: Uuid, ) -> Result { self.get(&format!( "/api/v1/directives/{}/evaluations", directive_id )) .await } // ========================================================================= // Verifiers // ========================================================================= /// List verifiers for a directive. pub async fn list_directive_verifiers( &self, directive_id: Uuid, ) -> Result { self.get(&format!("/api/v1/directives/{}/verifiers", directive_id)) .await } /// Add a verifier to a directive. pub async fn add_directive_verifier( &self, directive_id: Uuid, name: &str, verifier_type: &str, command: Option<&str>, ) -> Result { #[derive(serde::Serialize)] #[serde(rename_all = "camelCase")] struct CreateVerifierReq<'a> { name: &'a str, verifier_type: &'a str, #[serde(skip_serializing_if = "Option::is_none")] command: Option<&'a str>, } let req = CreateVerifierReq { name, verifier_type, command, }; self.post( &format!("/api/v1/directives/{}/verifiers", directive_id), &req, ) .await } /// Update a verifier. pub async fn update_directive_verifier( &self, directive_id: Uuid, verifier_id: Uuid, update: serde_json::Value, ) -> Result { self.put( &format!( "/api/v1/directives/{}/verifiers/{}", directive_id, verifier_id ), &update, ) .await } /// Auto-detect verifiers based on repository content. pub async fn auto_detect_directive_verifiers( &self, directive_id: Uuid, ) -> Result { self.post_empty(&format!( "/api/v1/directives/{}/verifiers/auto-detect", directive_id )) .await } // ========================================================================= // Requirements & Spec // ========================================================================= /// Update directive requirements. pub async fn update_directive_requirements( &self, directive_id: Uuid, requirements: serde_json::Value, ) -> Result { #[derive(serde::Serialize)] #[serde(rename_all = "camelCase")] struct UpdateReq { requirements: serde_json::Value, } let req = UpdateReq { requirements }; self.put( &format!("/api/v1/directives/{}/requirements", directive_id), &req, ) .await } /// Update directive acceptance criteria. pub async fn update_directive_criteria( &self, directive_id: Uuid, acceptance_criteria: serde_json::Value, ) -> Result { #[derive(serde::Serialize)] #[serde(rename_all = "camelCase")] struct UpdateReq { acceptance_criteria: serde_json::Value, } let req = UpdateReq { acceptance_criteria }; self.put( &format!("/api/v1/directives/{}/criteria", directive_id), &req, ) .await } /// Generate a specification from the directive's goal. pub async fn generate_directive_spec( &self, directive_id: Uuid, ) -> Result { self.post_empty(&format!( "/api/v1/directives/{}/generate-spec", directive_id )) .await } }