//! 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<JsonValue, ApiError> {
#[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<JsonValue, ApiError> {
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<JsonValue, ApiError> {
self.get(&format!("/api/v1/directives/{}", directive_id))
.await
}
/// Archive a directive.
pub async fn archive_directive(&self, directive_id: Uuid) -> Result<JsonValue, ApiError> {
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<JsonValue, ApiError> {
self.post_empty(&format!("/api/v1/directives/{}/start", directive_id))
.await
}
/// Pause a directive.
pub async fn pause_directive(&self, directive_id: Uuid) -> Result<JsonValue, ApiError> {
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<JsonValue, ApiError> {
self.post_empty(&format!("/api/v1/directives/{}/resume", directive_id))
.await
}
/// Stop a directive.
pub async fn stop_directive(&self, directive_id: Uuid) -> Result<JsonValue, ApiError> {
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<JsonValue, ApiError> {
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<JsonValue, ApiError> {
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<JsonValue, ApiError> {
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<JsonValue, ApiError> {
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<JsonValue, ApiError> {
#[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<JsonValue, ApiError> {
#[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<JsonValue, ApiError> {
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<Vec<Uuid>>,
) -> Result<JsonValue, ApiError> {
#[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<Vec<Uuid>>,
}
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<JsonValue, ApiError> {
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<JsonValue, ApiError> {
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<JsonValue, ApiError> {
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<JsonValue, ApiError> {
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<JsonValue, ApiError> {
#[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<JsonValue, ApiError> {
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<JsonValue, ApiError> {
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<JsonValue, ApiError> {
#[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<JsonValue, ApiError> {
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<JsonValue, ApiError> {
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<JsonValue, ApiError> {
#[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<JsonValue, ApiError> {
#[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<JsonValue, ApiError> {
self.post_empty(&format!(
"/api/v1/directives/{}/generate-spec",
directive_id
))
.await
}
}