diff --git a/crates/vapora-doc-lifecycle/Cargo.toml b/crates/vapora-doc-lifecycle/Cargo.toml new file mode 100644 index 0000000..e4e02fd --- /dev/null +++ b/crates/vapora-doc-lifecycle/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "vapora-doc-lifecycle" +version = "0.1.0" +edition = "2021" +authors = ["Jesus Perez "] +license = "MIT" +description = "VAPORA adapter for documentation lifecycle management" + +[dependencies] +doc-lifecycle-core = { path = "../../../Tools/doc-lifecycle-manager/crates/doc-lifecycle-core" } +tokio = { version = "1.35", features = ["full"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +tracing = "0.1" +anyhow = "1.0" +thiserror = "1.0" + +# VAPORA dependencies (will be added later) +# vapora-shared = { path = "../vapora-shared" } +# vapora-agents = { path = "../vapora-agents" } + +[dev-dependencies] +tempfile = "3.8" diff --git a/crates/vapora-doc-lifecycle/src/config.rs b/crates/vapora-doc-lifecycle/src/config.rs new file mode 100644 index 0000000..3202571 --- /dev/null +++ b/crates/vapora-doc-lifecycle/src/config.rs @@ -0,0 +1,55 @@ +//! Configuration for doc-lifecycle VAPORA adapter + +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; + +/// Plugin configuration +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PluginConfig { + /// Enable doc-lifecycle plugin + pub enabled: bool, + + /// Root directory for documentation + pub docs_root: PathBuf, + + /// Mode: minimal, standard, or full + pub mode: String, + + /// Classify on task completion + pub auto_classify: bool, + + /// Consolidate duplicates automatically + pub auto_consolidate: bool, + + /// Generate RAG index + pub generate_rag_index: bool, + + /// Generate mdBook site + pub generate_mdbook: bool, + + /// Language for documentation + pub language: String, + + /// NATS subject for task events + pub nats_subject: String, + + /// SurrealDB connection string + pub surreal_url: String, +} + +impl Default for PluginConfig { + fn default() -> Self { + Self { + enabled: true, + docs_root: PathBuf::from("docs"), + mode: "standard".to_string(), + auto_classify: true, + auto_consolidate: true, + generate_rag_index: true, + generate_mdbook: true, + language: "en".to_string(), + nats_subject: "vapora.tasks.completed".to_string(), + surreal_url: "surreal://localhost:8000".to_string(), + } + } +} diff --git a/crates/vapora-doc-lifecycle/src/documenter.rs b/crates/vapora-doc-lifecycle/src/documenter.rs new file mode 100644 index 0000000..ce1081e --- /dev/null +++ b/crates/vapora-doc-lifecycle/src/documenter.rs @@ -0,0 +1,56 @@ +//! Documenter agent integration with doc-lifecycle + +use crate::config::PluginConfig; +use crate::plugin::DocLifecyclePlugin; +use crate::Result; + +/// Documenter agent integration +#[derive(Debug)] +pub struct DocumenterIntegration { + plugin: DocLifecyclePlugin, + config: PluginConfig, +} + +impl DocumenterIntegration { + /// Create a new documenter integration + pub fn new(config: PluginConfig) -> Result { + let plugin = DocLifecyclePlugin::new(config.clone())?; + + Ok(Self { plugin, config }) + } + + /// Handle task completion event + pub async fn on_task_completed(&mut self, task_id: &str) -> Result<()> { + tracing::info!( + "Documenter: Processing task completion for task {}", + task_id + ); + + // 1. Process documentation + self.plugin.process_task_docs(task_id).await?; + + // 2. Update root files (README, CHANGELOG, ROADMAP) + self.update_root_files(task_id).await?; + + // 3. Publish event for other agents + self.publish_docs_updated_event(task_id).await?; + + Ok(()) + } + + async fn update_root_files(&self, _task_id: &str) -> Result<()> { + // TODO: Update README, CHANGELOG, ROADMAP + Ok(()) + } + + async fn publish_docs_updated_event(&self, _task_id: &str) -> Result<()> { + // TODO: Publish to NATS + Ok(()) + } + + /// Get current configuration + #[must_use] + pub fn config(&self) -> &PluginConfig { + &self.config + } +} diff --git a/crates/vapora-doc-lifecycle/src/error.rs b/crates/vapora-doc-lifecycle/src/error.rs new file mode 100644 index 0000000..632b24b --- /dev/null +++ b/crates/vapora-doc-lifecycle/src/error.rs @@ -0,0 +1,41 @@ +//! Error types for VAPORA doc-lifecycle adapter + +use std::fmt; + +/// Result type for adapter operations +pub type Result = std::result::Result; + +/// Error type for adapter operations +#[derive(Debug)] +pub enum Error { + /// Core library error + Core(doc_lifecycle_core::Error), + /// Configuration error + Config(String), + /// NATS error + NatsError(String), + /// Database error + DatabaseError(String), + /// Other errors + Other(Box), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Core(e) => write!(f, "Core error: {}", e), + Self::Config(msg) => write!(f, "Config error: {}", msg), + Self::NatsError(msg) => write!(f, "NATS error: {}", msg), + Self::DatabaseError(msg) => write!(f, "Database error: {}", msg), + Self::Other(e) => write!(f, "{}", e), + } + } +} + +impl std::error::Error for Error {} + +impl From for Error { + fn from(err: doc_lifecycle_core::Error) -> Self { + Self::Core(err) + } +} diff --git a/crates/vapora-doc-lifecycle/src/lib.rs b/crates/vapora-doc-lifecycle/src/lib.rs new file mode 100644 index 0000000..15aa2f8 --- /dev/null +++ b/crates/vapora-doc-lifecycle/src/lib.rs @@ -0,0 +1,28 @@ +//! VAPORA Documentation Lifecycle Management Adapter +//! +//! This crate provides integration between VAPORA's agent orchestration +//! and the doc-lifecycle-core library. +//! +//! Features: +//! - Event-driven documentation processing +//! - NATS JetStream integration for task events +//! - SurrealDB vector store for RAG indexing +//! - Automatic triggering on task completion + +#![warn(missing_docs)] +#![warn(missing_debug_implementations)] + +pub mod plugin; +pub mod documenter; +pub mod config; +pub mod error; + +pub use error::{Error, Result}; + +/// Re-export commonly used types +pub mod prelude { + pub use crate::plugin::DocLifecyclePlugin; + pub use crate::documenter::DocumenterIntegration; + pub use crate::config::PluginConfig; + pub use crate::{Error, Result}; +} diff --git a/crates/vapora-doc-lifecycle/src/plugin.rs b/crates/vapora-doc-lifecycle/src/plugin.rs new file mode 100644 index 0000000..dff318f --- /dev/null +++ b/crates/vapora-doc-lifecycle/src/plugin.rs @@ -0,0 +1,88 @@ +//! Doc-lifecycle plugin for VAPORA + +use crate::config::PluginConfig; +use crate::Result; +use doc_lifecycle_core::prelude::*; +use std::path::PathBuf; + +/// Main plugin interface for doc-lifecycle integration +#[derive(Debug)] +pub struct DocLifecyclePlugin { + config: PluginConfig, + classifier: Classifier, + consolidator: Consolidator, + rag_indexer: RagIndexer, + mdbook_generator: Option, +} + +impl DocLifecyclePlugin { + /// Create a new doc-lifecycle plugin + pub fn new(config: PluginConfig) -> Result { + let mdbook_generator = if config.generate_mdbook { + let mdbook_config = doc_lifecycle_core::mdbook_generator::MdBookConfig::new( + PathBuf::from("book"), + "VAPORA Project".to_string(), + ); + Some(MdBookGenerator::new(mdbook_config)) + } else { + None + }; + + Ok(Self { + config, + classifier: Classifier::new(), + consolidator: Consolidator::new(), + rag_indexer: RagIndexer::new(), + mdbook_generator, + }) + } + + /// Process documentation for a completed task + pub async fn process_task_docs(&mut self, task_id: &str) -> Result<()> { + tracing::info!("Processing task docs for task {}", task_id); + + // 1. Classify documents + if self.config.auto_classify { + self.classify_session_docs(task_id).await?; + } + + // 2. Consolidate duplicates + if self.config.auto_consolidate { + self.consolidate_docs().await?; + } + + // 3. Generate RAG index + if self.config.generate_rag_index { + self.update_rag_index().await?; + } + + // 4. Generate mdBook + if self.config.generate_mdbook { + self.generate_mdbook().await?; + } + + Ok(()) + } + + async fn classify_session_docs(&self, _task_id: &str) -> Result<()> { + // TODO: Implement session doc classification + Ok(()) + } + + async fn consolidate_docs(&self) -> Result<()> { + // TODO: Implement consolidation + Ok(()) + } + + async fn update_rag_index(&self) -> Result<()> { + // TODO: Implement RAG index update + Ok(()) + } + + async fn generate_mdbook(&self) -> Result<()> { + if let Some(generator) = &self.mdbook_generator { + generator.generate()?; + } + Ok(()) + } +}