diff options
| author | soryu <soryu@soryu.co> | 2026-02-05 23:42:48 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-02-05 23:42:48 +0000 |
| commit | 88a4f15ce1310f8ee8693835be14aa5280233f17 (patch) | |
| tree | 5c1a0417e02071d2198d13478ffa85533b19f891 /makima/src/daemon/api | |
| parent | f1a50b80f3969d150bd1c31edde0aff05369157e (diff) | |
| download | soryu-88a4f15ce1310f8ee8693835be14aa5280233f17.tar.gz soryu-88a4f15ce1310f8ee8693835be14aa5280233f17.zip | |
Add directive-first chain system redesign
Redesigns the chain system with a directive-first architecture where
Directive is the top-level entity (the "why/what") and Chains are
generated execution plans (the "how") that can be dynamically modified.
Backend:
- Add database migration for directive system tables
- Add Directive, DirectiveChain, ChainStep, DirectiveEvent models
- Add DirectiveVerifier and DirectiveApproval models
- Add orchestration module with engine, planner, and verifier
- Add comprehensive API handlers for directives
- Add daemon CLI commands for directive management
- Add directive skill documentation
- Integrate contract completion with directive engine
- Add SSE endpoint for real-time directive events
Frontend:
- Add directives route with split-view layout
- Add 6-tab detail view (Overview, Chain, Events, Evaluations, Approvals, Verifiers)
- Add React Flow DAG visualization for chain steps
- Add SSE subscription hook for real-time event updates
- Add useDirectives and useDirectiveEventSubscription hooks
- Add directive types and API functions
Fixes:
- Fix test failures in ws/protocol, task_output, completion_gate, patch
- Fix word boundary matching in looks_like_task()
- Fix parse_last() to find actual last completion gate
- Fix create_export_patch when merge-base equals HEAD
- Clean up clippy warnings in new code
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'makima/src/daemon/api')
| -rw-r--r-- | makima/src/daemon/api/directive.rs | 162 | ||||
| -rw-r--r-- | makima/src/daemon/api/mod.rs | 1 |
2 files changed, 163 insertions, 0 deletions
diff --git a/makima/src/daemon/api/directive.rs b/makima/src/daemon/api/directive.rs new file mode 100644 index 0000000..5281d21 --- /dev/null +++ b/makima/src/daemon/api/directive.rs @@ -0,0 +1,162 @@ +//! 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 + } +} diff --git a/makima/src/daemon/api/mod.rs b/makima/src/daemon/api/mod.rs index 7868907..f1f52d0 100644 --- a/makima/src/daemon/api/mod.rs +++ b/makima/src/daemon/api/mod.rs @@ -3,6 +3,7 @@ pub mod chain; pub mod client; pub mod contract; +pub mod directive; pub mod supervisor; pub use client::ApiClient; |
