agtrace-runtime 0.7.1

Internal runtime orchestration for the agtrace CLI. Not intended for direct use.
Documentation
use crate::runtime::{SessionStreamer, WatchContext, WorkspaceEvent, WorkspaceSupervisor};
use crate::{Error, Result};
use agtrace_index::Database;
use std::path::PathBuf;
use std::sync::mpsc::Receiver;
use std::sync::{Arc, Mutex};

pub struct MonitorBuilder {
    db: Arc<Mutex<Database>>,
    provider_configs: Arc<Vec<(String, PathBuf)>>,
    project_root: Option<PathBuf>,
}

impl MonitorBuilder {
    pub fn new(db: Arc<Mutex<Database>>, provider_configs: Arc<Vec<(String, PathBuf)>>) -> Self {
        Self {
            db,
            provider_configs,
            project_root: None,
        }
    }

    pub fn with_project_root(mut self, project_root: PathBuf) -> Self {
        self.project_root = Some(project_root);
        self
    }

    pub fn start_background_scan(self) -> Result<WorkspaceMonitor> {
        let mut contexts = Vec::new();

        for (provider_name, root) in self.provider_configs.iter() {
            if let Ok(adapter) = agtrace_providers::create_adapter(provider_name) {
                contexts.push(WatchContext {
                    provider_name: provider_name.clone(),
                    provider: Arc::new(adapter),
                    root: root.clone(),
                });
            }
        }

        let supervisor = WorkspaceSupervisor::start(contexts, self.db.clone(), self.project_root)?;

        Ok(WorkspaceMonitor {
            db: self.db,
            supervisor,
            provider_configs: self.provider_configs,
        })
    }
}

pub struct WorkspaceMonitor {
    db: Arc<Mutex<Database>>,
    supervisor: WorkspaceSupervisor,
    provider_configs: Arc<Vec<(String, PathBuf)>>,
}

impl WorkspaceMonitor {
    pub fn receiver(&self) -> &Receiver<WorkspaceEvent> {
        self.supervisor.receiver()
    }

    pub fn next_event(&self) -> Option<WorkspaceEvent> {
        self.supervisor.receiver().recv().ok()
    }

    pub fn attach(&self, session_id: &str, provider_name: Option<&str>) -> Result<StreamHandle> {
        let provider_name = if let Some(name) = provider_name {
            name.to_string()
        } else {
            self.provider_configs
                .first()
                .map(|(n, _)| n.clone())
                .ok_or_else(|| Error::InvalidOperation("No providers available".to_string()))?
        };

        let adapter = agtrace_providers::create_adapter(&provider_name)?;

        let streamer =
            SessionStreamer::attach(session_id.to_string(), self.db.clone(), Arc::new(adapter))?;

        Ok(StreamHandle { streamer })
    }
}

pub struct StreamHandle {
    streamer: SessionStreamer,
}

impl StreamHandle {
    pub(crate) fn new(streamer: SessionStreamer) -> Self {
        Self { streamer }
    }

    pub fn receiver(&self) -> &Receiver<WorkspaceEvent> {
        self.streamer.receiver()
    }
}