Skip to main content

oxios_kernel/kernel_handle/
infra_api.rs

1//! Infra API — Git, cron, resources, events, system.
2
3use crate::ToolMeta;
4use crate::config::OxiosConfig;
5use crate::cron::{CronJob, CronJobUpdate, CronScheduler};
6use crate::event_bus::{EventBus, KernelEvent};
7use crate::git_layer::{GitLayer, LogEntry};
8use crate::resource_monitor::{ResourceMonitor, ResourceSnapshot};
9use crate::tools::{PendingAskUser, PendingToolApprovals, known_tools};
10use std::sync::Arc;
11use std::time::{Duration, Instant};
12
13/// Infrastructure system calls.
14pub struct InfraApi {
15    pub(crate) git_layer: Arc<GitLayer>,
16    pub(crate) cron_scheduler: Arc<CronScheduler>,
17    pub(crate) resource_monitor: Arc<ResourceMonitor>,
18    pub(crate) event_bus: EventBus,
19    pub(crate) config: OxiosConfig,
20    pub(crate) start_time: Instant,
21    /// Hot-reloadable orchestrator config (evolution iterations, score threshold).
22    pub(crate) orchestrator_config: parking_lot::RwLock<crate::config::OrchestratorConfig>,
23    pub(crate) approval_config: Arc<parking_lot::RwLock<crate::approval::ApprovalConfig>>,
24    /// Pending tool approval requests (HitL escalation).
25    pub(crate) pending_tool_approvals: Arc<PendingToolApprovals>,
26    /// Pending `ask_user` requests (RFC-027 agent-driven clarification).
27    pub(crate) pending_ask_user: Arc<PendingAskUser>,
28}
29
30impl InfraApi {
31    /// Create a new InfraApi.
32    // Facade construction gathers the independent infrastructure services.
33    #[allow(clippy::too_many_arguments)]
34    pub fn new(
35        git_layer: Arc<GitLayer>,
36        cron_scheduler: Arc<CronScheduler>,
37        resource_monitor: Arc<ResourceMonitor>,
38        event_bus: EventBus,
39        config: OxiosConfig,
40        start_time: Instant,
41        pending_tool_approvals: Arc<PendingToolApprovals>,
42        pending_ask_user: Arc<PendingAskUser>,
43    ) -> Self {
44        let approval_config = config.security.approval.clone();
45        Self {
46            git_layer,
47            cron_scheduler,
48            resource_monitor,
49            event_bus,
50            config,
51            start_time,
52            orchestrator_config: parking_lot::RwLock::new(
53                crate::config::OrchestratorConfig::default(),
54            ),
55            approval_config: Arc::new(parking_lot::RwLock::new(approval_config)),
56            pending_tool_approvals,
57            pending_ask_user,
58        }
59    }
60    /// Get a reference to the GitLayer.
61    pub fn git(&self) -> &GitLayer {
62        &self.git_layer
63    }
64
65    pub fn approval_config_handle(
66        &self,
67    ) -> Arc<parking_lot::RwLock<crate::approval::ApprovalConfig>> {
68        Arc::clone(&self.approval_config)
69    }
70    pub fn approval_config(&self) -> crate::approval::ApprovalConfig {
71        self.approval_config.read().clone()
72    }
73
74    pub async fn set_approval_config(
75        &self,
76        config: crate::approval::ApprovalConfig,
77    ) -> anyhow::Result<crate::approval::ApprovalConfig> {
78        *self.approval_config.write() = config.clone();
79        Ok(config)
80    }
81
82    pub async fn add_grant(&self, key: String) -> anyhow::Result<crate::approval::ApprovalConfig> {
83        let mut config = self.approval_config();
84        if !config.allow_list.contains(&key) {
85            config.allow_list.push(key);
86        }
87        self.set_approval_config(config.clone()).await
88    }
89
90    pub async fn remove_grant(&self, key: &str) -> anyhow::Result<crate::approval::ApprovalConfig> {
91        let mut config = self.approval_config();
92        config.allow_list.retain(|item| item != key);
93        self.set_approval_config(config.clone()).await
94    }
95
96    /// Get commit log.
97    pub fn git_log(&self, max: usize) -> anyhow::Result<Vec<LogEntry>> {
98        self.git_layer.log(max)
99    }
100
101    /// Tag current state.
102    pub fn git_tag(&self, name: &str, message: &str) -> anyhow::Result<()> {
103        self.git_layer.tag(name, message)
104    }
105
106    /// Restore file from commit.
107    pub fn git_restore(&self, path: &str, hash: &str) -> anyhow::Result<()> {
108        self.git_layer.restore_file(path, hash)
109    }
110
111    /// Verify git repository integrity.
112    pub fn git_verify(&self) -> anyhow::Result<bool> {
113        self.git_layer.verify()
114    }
115
116    /// List git tags.
117    pub fn git_tags(&self) -> anyhow::Result<Vec<String>> {
118        self.git_layer.list_tags()
119    }
120
121    /// Delete a tag by name.
122    pub fn git_delete_tag(&self, name: &str) -> anyhow::Result<()> {
123        self.git_layer.delete_tag(name)
124    }
125
126    /// Add a cron job.
127    pub async fn add_cron(&self, job: CronJob) -> anyhow::Result<uuid::Uuid> {
128        self.cron_scheduler.add_job(job).await
129    }
130
131    /// Get a cron job by ID.
132    pub fn get_cron(&self, id: uuid::Uuid) -> Option<CronJob> {
133        self.cron_scheduler.get_job(id)
134    }
135
136    /// Update a cron job.
137    pub async fn update_cron(&self, id: uuid::Uuid, update: CronJobUpdate) -> anyhow::Result<()> {
138        self.cron_scheduler.update_job(id, update).await
139    }
140
141    /// Remove a cron job by ID.
142    pub async fn remove_cron(&self, id: uuid::Uuid) -> anyhow::Result<()> {
143        self.cron_scheduler.remove_job(id).await
144    }
145
146    /// Trigger a cron job manually.
147    pub fn trigger_cron(&self, id: uuid::Uuid) -> anyhow::Result<CronJob> {
148        self.cron_scheduler.trigger_job(id)
149    }
150
151    /// Mark cron job completed.
152    pub async fn complete_cron(&self, id: uuid::Uuid, success: bool, summary: String) {
153        self.cron_scheduler
154            .mark_job_completed(id, success, summary)
155            .await
156    }
157
158    /// List all cron jobs.
159    pub fn list_crons(&self) -> Vec<CronJob> {
160        self.cron_scheduler.list_jobs()
161    }
162
163    /// Get resource snapshot.
164    pub fn resource_snapshot(&self) -> ResourceSnapshot {
165        self.resource_monitor.snapshot()
166    }
167
168    /// Get resource history snapshots.
169    pub fn resource_history(&self, last_n: usize) -> Vec<ResourceSnapshot> {
170        self.resource_monitor.history(last_n)
171    }
172
173    /// Check if system is overloaded.
174    pub fn is_overloaded(&self) -> bool {
175        self.resource_monitor.is_overloaded()
176    }
177
178    /// Subscribe to kernel events.
179    pub fn subscribe(&self) -> tokio::sync::broadcast::Receiver<KernelEvent> {
180        self.event_bus.subscribe()
181    }
182
183    /// Publish a kernel event.
184    pub fn publish(&self, event: KernelEvent) -> anyhow::Result<()> {
185        self.event_bus
186            .publish(event)
187            .map_err(|e| anyhow::anyhow!("broadcast error: {e}"))
188    }
189
190    /// Get config reference.
191    pub fn config(&self) -> &OxiosConfig {
192        &self.config
193    }
194
195    /// Resource monitor reference — for hot-reload config propagation.
196    pub fn resource_monitor(&self) -> &Arc<ResourceMonitor> {
197        &self.resource_monitor
198    }
199
200    /// Hot-reload orchestrator config (stored in InfraApi for propagation).
201    pub fn update_orchestrator_config(&self, config: crate::config::OrchestratorConfig) {
202        *self.orchestrator_config.write() = config;
203    }
204
205    /// Get system uptime.
206    pub fn uptime(&self) -> Duration {
207        self.start_time.elapsed()
208    }
209
210    /// Access the pending tool approvals registry.
211    pub fn pending_tool_approvals(&self) -> Arc<PendingToolApprovals> {
212        self.pending_tool_approvals.clone()
213    }
214
215    /// Access the pending `ask_user` registry (RFC-027 agent-driven clarification).
216    pub fn pending_ask_user(&self) -> Arc<PendingAskUser> {
217        Arc::clone(&self.pending_ask_user)
218    }
219
220    /// Clone the underlying event bus so tools can publish `KernelEvent`s
221    /// without routing through the wrapping `publish` helper.
222    pub fn event_bus_clone(&self) -> EventBus {
223        self.event_bus.clone()
224    }
225
226    /// List all known tool metadata (static catalog).
227    pub fn list_available_tools(&self) -> &'static [ToolMeta] {
228        known_tools()
229    }
230}