diff --git a/server/src/agents/mod.rs b/server/src/agents/mod.rs index 939b5fec..28be75f7 100644 --- a/server/src/agents/mod.rs +++ b/server/src/agents/mod.rs @@ -1,12 +1,19 @@ //! Agent subsystem — types, configuration, and orchestration for coding agents. +/// Acceptance-gate checks (clippy, tests, doc coverage). pub mod gates; +/// Agent start/stop and pipeline advancement on completion. pub mod lifecycle; +/// Constructs the system prompt sent to coding agents. pub mod local_prompt; +/// Merge-conflict resolution helpers. pub mod merge; pub(crate) mod pool; pub(crate) mod pty; +/// Runtime backends (Claude Code, OpenAI, Gemini) that execute agent sessions. pub mod runtime; +/// Persistent session-ID storage for agent resume support. pub mod session_store; +/// Token-usage tracking and budget estimation. pub mod token_usage; use crate::config::AgentConfig; @@ -74,6 +81,7 @@ pub enum AgentEvent { #[derive(Debug, Clone, Serialize, PartialEq)] #[serde(rename_all = "snake_case")] +/// Lifecycle state of an agent session. pub enum AgentStatus { Pending, Running, @@ -212,6 +220,7 @@ impl TokenUsage { } #[derive(Debug, Serialize, Clone)] +/// Snapshot of a running or completed agent, exposed via the HTTP API. pub struct AgentInfo { pub story_id: String, pub agent_name: String, diff --git a/server/src/agents/pool/mod.rs b/server/src/agents/pool/mod.rs index d17a0e79..bc233607 100644 --- a/server/src/agents/pool/mod.rs +++ b/server/src/agents/pool/mod.rs @@ -48,6 +48,7 @@ pub struct AgentPool { } impl AgentPool { + /// Create a new agent pool bound to the given HTTP port and event channel. pub fn new(port: u16, watcher_tx: broadcast::Sender) -> Self { let pool = Self { agents: Arc::new(Mutex::new(HashMap::new())), @@ -98,6 +99,7 @@ impl AgentPool { pool } + /// Return the HTTP port this pool's agents connect to. pub fn port(&self) -> u16 { self.port } diff --git a/server/src/agents/runtime/claude_code.rs b/server/src/agents/runtime/claude_code.rs index 9a43edec..06e70e1a 100644 --- a/server/src/agents/runtime/claude_code.rs +++ b/server/src/agents/runtime/claude_code.rs @@ -22,6 +22,7 @@ pub struct ClaudeCodeRuntime { } impl ClaudeCodeRuntime { + /// Create a new Claude Code runtime with shared child-killer registry and event channel. pub fn new( child_killers: Arc>>>, watcher_tx: broadcast::Sender, diff --git a/server/src/agents/runtime/gemini/mod.rs b/server/src/agents/runtime/gemini/mod.rs index 924dc477..9e1183af 100644 --- a/server/src/agents/runtime/gemini/mod.rs +++ b/server/src/agents/runtime/gemini/mod.rs @@ -43,6 +43,7 @@ pub struct GeminiRuntime { } impl GeminiRuntime { + /// Create a new Gemini runtime instance. pub fn new() -> Self { Self { cancelled: Arc::new(AtomicBool::new(false)), diff --git a/server/src/agents/runtime/openai.rs b/server/src/agents/runtime/openai.rs index ea4809eb..8ff58007 100644 --- a/server/src/agents/runtime/openai.rs +++ b/server/src/agents/runtime/openai.rs @@ -30,6 +30,7 @@ pub struct OpenAiRuntime { } impl OpenAiRuntime { + /// Create a new OpenAI runtime instance. pub fn new() -> Self { Self { cancelled: Arc::new(AtomicBool::new(false)), diff --git a/server/src/chat/mod.rs b/server/src/chat/mod.rs index 2a7c129b..2a7c66f8 100644 --- a/server/src/chat/mod.rs +++ b/server/src/chat/mod.rs @@ -4,13 +4,18 @@ //! sending and editing messages, allowing the bot logic (commands, htop, //! notifications) to work against any chat platform — Matrix, WhatsApp, etc. +/// Bot command registry and dispatch — parses and routes incoming chat messages. pub mod commands; +/// Chat history utilities — loading and serialising conversation history. pub mod history; pub(crate) mod lookup; #[cfg(test)] pub(crate) mod test_helpers; +/// Rate-limit retry timers — stores and fires scheduled retry reminders. pub mod timer; +/// Platform transports — pluggable backends (Matrix, Slack, WhatsApp, Discord). pub mod transport; +/// Chat utility functions — shared helpers for message formatting and bot logic. pub mod util; use async_trait::async_trait; diff --git a/server/src/chat/transport/discord/meta.rs b/server/src/chat/transport/discord/meta.rs index 84939796..fe0cd78d 100644 --- a/server/src/chat/transport/discord/meta.rs +++ b/server/src/chat/transport/discord/meta.rs @@ -25,6 +25,7 @@ pub struct DiscordTransport { } impl DiscordTransport { + /// Creates a new `DiscordTransport` authenticated with the given bot token. pub fn new(bot_token: String) -> Self { Self { bot_token, diff --git a/server/src/chat/transport/discord/mod.rs b/server/src/chat/transport/discord/mod.rs index 04503a82..a6b895c8 100644 --- a/server/src/chat/transport/discord/mod.rs +++ b/server/src/chat/transport/discord/mod.rs @@ -7,10 +7,15 @@ //! receives `MESSAGE_CREATE` events, and dispatches commands. //! - [`DiscordContext`] — shared context for the bot. +/// Discord bot command handlers — parses and dispatches bot commands from Discord messages. pub mod commands; +/// Discord message formatter — converts markdown to Discord-compatible markup. pub mod format; +/// Discord Gateway WebSocket — connects to the Discord Gateway and handles MESSAGE_CREATE events. pub mod gateway; +/// Discord conversation history — loads prior chat history for context. pub mod history; +/// DiscordTransport — `ChatTransport` implementation for the Discord Bot API. pub mod meta; pub use commands::DiscordContext; diff --git a/server/src/chat/transport/matrix/bot/mod.rs b/server/src/chat/transport/matrix/bot/mod.rs index cca76224..3421088b 100644 --- a/server/src/chat/transport/matrix/bot/mod.rs +++ b/server/src/chat/transport/matrix/bot/mod.rs @@ -1,10 +1,17 @@ //! Matrix bot — sub-modules for the Matrix chat bot implementation. +/// Bot context — shared state passed to Matrix bot command handlers. pub mod context; +/// Matrix message formatter — converts markdown to Matrix HTML. pub mod format; +/// Conversation history — loads and saves per-room chat history. pub mod history; +/// Mention detection — identifies messages that mention the bot user. pub mod mentions; +/// Message handlers — processes incoming Matrix room messages. pub mod messages; +/// Bot run loop — the main async task that drives the Matrix sync loop. pub mod run; +/// Device verification — handles Matrix cross-signing and emoji verification flows. pub mod verification; // Re-export all public types so existing import paths continue to work. diff --git a/server/src/chat/transport/matrix/mod.rs b/server/src/chat/transport/matrix/mod.rs index c1f0a4c0..c0889f6e 100644 --- a/server/src/chat/transport/matrix/mod.rs +++ b/server/src/chat/transport/matrix/mod.rs @@ -15,16 +15,25 @@ //! Multi-room support: configure `room_ids = ["!room1:…", "!room2:…"]` in //! `bot.toml`. Each room maintains its own independent conversation history. +/// Auto-assign handler — listens for pipeline events and assigns stories to free agents. pub mod assign; mod bot; +/// Matrix bot command handlers — parses and routes bot commands from Matrix messages. pub mod commands; pub(crate) mod config; +/// Story deletion command — handles `!delete` bot commands to remove work items. pub mod delete; +/// htop-style agent monitor command — renders a live process table in Matrix. pub mod htop; +/// Rebuild command — triggers a server rebuild/restart via a bot command. pub mod rebuild; +/// Reset command — handles `!reset` bot commands to restart the server state. pub mod reset; +/// rmtree command — handles `!rmtree` bot commands to remove worktrees. pub mod rmtree; +/// Start command — handles `!start` bot commands to launch agents on stories. pub mod start; +/// Matrix `ChatTransport` implementation wrapping the Matrix SDK client. pub mod transport_impl; pub use bot::{ConversationEntry, ConversationRole, RoomConversation}; diff --git a/server/src/chat/transport/matrix/transport_impl.rs b/server/src/chat/transport/matrix/transport_impl.rs index 9b8cee0c..b6d73534 100644 --- a/server/src/chat/transport/matrix/transport_impl.rs +++ b/server/src/chat/transport/matrix/transport_impl.rs @@ -20,6 +20,7 @@ pub struct MatrixTransport { } impl MatrixTransport { + /// Creates a new `MatrixTransport` wrapping the given Matrix SDK `Client`. pub fn new(client: Client) -> Self { Self { client } } diff --git a/server/src/chat/transport/mod.rs b/server/src/chat/transport/mod.rs index 190f397f..c0a69eb0 100644 --- a/server/src/chat/transport/mod.rs +++ b/server/src/chat/transport/mod.rs @@ -1,5 +1,9 @@ //! Chat transports — pluggable backends (Matrix, Slack, WhatsApp, Discord) for bot messaging. +/// Discord bot transport — sends and receives messages via the Discord REST/Gateway APIs. pub mod discord; +/// Matrix bot transport — sends messages via the Matrix SDK and runs the sync loop. pub mod matrix; +/// Slack bot transport — sends messages via the Slack Web API and handles webhook events. pub mod slack; +/// WhatsApp transport — sends messages via Meta Cloud API and Twilio API. pub mod whatsapp; diff --git a/server/src/chat/transport/slack/meta.rs b/server/src/chat/transport/slack/meta.rs index 6cd88849..9ff3a517 100644 --- a/server/src/chat/transport/slack/meta.rs +++ b/server/src/chat/transport/slack/meta.rs @@ -24,6 +24,7 @@ pub struct SlackTransport { } impl SlackTransport { + /// Creates a new `SlackTransport` authenticated with the given bot token. pub fn new(bot_token: String) -> Self { Self { bot_token, diff --git a/server/src/chat/transport/slack/mod.rs b/server/src/chat/transport/slack/mod.rs index cf5f2389..ecce2c5e 100644 --- a/server/src/chat/transport/slack/mod.rs +++ b/server/src/chat/transport/slack/mod.rs @@ -6,10 +6,15 @@ //! - [`webhook_receive`] — Poem handler for the Slack Events API webhook //! (POST incoming events including URL verification challenge). +/// Slack bot command handlers — parses and dispatches bot commands from Slack messages. pub mod commands; +/// Slack message formatter — converts markdown to Slack mrkdwn syntax. pub mod format; +/// Slack conversation history — loads prior chat history for context. pub mod history; +/// SlackTransport — `ChatTransport` implementation for the Slack Bot API. pub mod meta; +/// Slack request signature verification — validates HMAC-SHA256 signatures on incoming webhooks. pub mod verify; pub use commands::SlackWebhookContext; @@ -38,6 +43,7 @@ pub struct SlackEventEnvelope { pub event: Option, } +/// A single Slack event payload (message, reaction, etc.) nested inside an event callback. #[derive(Deserialize, Debug)] pub struct SlackEvent { pub r#type: Option, diff --git a/server/src/chat/transport/whatsapp/meta.rs b/server/src/chat/transport/whatsapp/meta.rs index abcc00d3..965615d9 100644 --- a/server/src/chat/transport/whatsapp/meta.rs +++ b/server/src/chat/transport/whatsapp/meta.rs @@ -40,6 +40,7 @@ pub struct WhatsAppTransport { } impl WhatsAppTransport { + /// Creates a new `WhatsAppTransport` authenticated with the given Meta Cloud API credentials. pub fn new( phone_number_id: String, access_token: String, diff --git a/server/src/chat/transport/whatsapp/twilio.rs b/server/src/chat/transport/whatsapp/twilio.rs index c7bbc111..09cfaf51 100644 --- a/server/src/chat/transport/whatsapp/twilio.rs +++ b/server/src/chat/transport/whatsapp/twilio.rs @@ -29,6 +29,7 @@ pub struct TwilioWhatsAppTransport { } impl TwilioWhatsAppTransport { + /// Creates a new `TwilioWhatsAppTransport` authenticated with the given Twilio credentials. pub fn new(account_sid: String, auth_token: String, from_number: String) -> Self { Self { account_sid, diff --git a/server/src/config/mod.rs b/server/src/config/mod.rs index ae45c170..fec185ed 100644 --- a/server/src/config/mod.rs +++ b/server/src/config/mod.rs @@ -4,6 +4,7 @@ use serde::Deserialize; use std::collections::HashSet; use std::path::Path; +/// Top-level project configuration loaded from `.huskies/project.toml`. #[derive(Debug, Clone, Deserialize)] pub struct ProjectConfig { #[serde(default)] @@ -195,6 +196,7 @@ fn default_max_mesh_peers() -> usize { 3 } +/// Configuration for a project component (name, path, setup/teardown commands). #[derive(Debug, Clone, Deserialize)] #[allow(dead_code)] pub struct ComponentConfig { @@ -207,6 +209,7 @@ pub struct ComponentConfig { pub teardown: Vec, } +/// Configuration for a single agent definition from `[[agent]]` in `project.toml`. #[derive(Debug, Clone, Deserialize)] pub struct AgentConfig { #[serde(default = "default_agent_name")] diff --git a/server/src/crdt_state/mod.rs b/server/src/crdt_state/mod.rs index b6bb5894..e7276fc6 100644 --- a/server/src/crdt_state/mod.rs +++ b/server/src/crdt_state/mod.rs @@ -62,6 +62,7 @@ pub(crate) use state::{ALL_OPS, VECTOR_CLOCK}; /// Hex-encode a byte slice (no external dep needed). pub(crate) mod hex { + /// Encode `bytes` as a lowercase hexadecimal string. pub fn encode(bytes: &[u8]) -> String { bytes.iter().map(|b| format!("{b:02x}")).collect() } diff --git a/server/src/crdt_state/types.rs b/server/src/crdt_state/types.rs index febbcb9b..6f7f6bb7 100644 --- a/server/src/crdt_state/types.rs +++ b/server/src/crdt_state/types.rs @@ -43,6 +43,7 @@ pub struct GatewayConfigCrdt { pub active_project: LwwRegisterCrdt, } +/// Top-level CRDT document holding all replicated pipeline state (items, nodes, jobs, etc.). #[add_crdt_fields] #[derive(Clone, CrdtNode, Debug)] pub struct PipelineDoc { @@ -57,6 +58,7 @@ pub struct PipelineDoc { pub gateway_config: GatewayConfigCrdt, } +/// CRDT sub-document representing a single pipeline work item with LWW fields for stage, agent, etc. #[add_crdt_fields] #[derive(Clone, CrdtNode, Debug)] pub struct PipelineItemCrdt { diff --git a/server/src/http/agents/mod.rs b/server/src/http/agents/mod.rs index c94d51c3..5aff6d85 100644 --- a/server/src/http/agents/mod.rs +++ b/server/src/http/agents/mod.rs @@ -200,6 +200,7 @@ fn map_svc_error(err: svc::Error) -> poem::Error { } } +/// OpenAPI endpoint group for agent management (start, stop, list, inspect). pub struct AgentsApi { pub ctx: Arc, } diff --git a/server/src/http/anthropic.rs b/server/src/http/anthropic.rs index dc0ddcb3..1aa8d09b 100644 --- a/server/src/http/anthropic.rs +++ b/server/src/http/anthropic.rs @@ -15,11 +15,13 @@ enum AnthropicTags { Anthropic, } +/// OpenAPI endpoint group for Anthropic API key and model operations. pub struct AnthropicApi { ctx: Arc, } impl AnthropicApi { + /// Create a new `AnthropicApi` bound to the given application context. pub fn new(ctx: Arc) -> Self { Self { ctx } } diff --git a/server/src/http/bot_command.rs b/server/src/http/bot_command.rs index c532d394..64957b0b 100644 --- a/server/src/http/bot_command.rs +++ b/server/src/http/bot_command.rs @@ -36,6 +36,7 @@ struct BotCommandResponse { response: String, } +/// OpenAPI endpoint group for bot slash-command execution. pub struct BotCommandApi { pub ctx: Arc, } diff --git a/server/src/http/bot_config.rs b/server/src/http/bot_config.rs index 0e114680..a73a05cd 100644 --- a/server/src/http/bot_config.rs +++ b/server/src/http/bot_config.rs @@ -22,6 +22,7 @@ struct BotConfigPayload { pub slack_channel_ids: Option>, } +/// OpenAPI endpoint group for reading and writing bot configuration. pub struct BotConfigApi { pub ctx: Arc, } diff --git a/server/src/http/chat.rs b/server/src/http/chat.rs index fccd099a..182d4545 100644 --- a/server/src/http/chat.rs +++ b/server/src/http/chat.rs @@ -9,6 +9,7 @@ enum ChatTags { Chat, } +/// OpenAPI endpoint group for the LLM-powered chat interface. pub struct ChatApi { pub ctx: Arc, } diff --git a/server/src/http/context.rs b/server/src/http/context.rs index 593f6641..71951e9a 100644 --- a/server/src/http/context.rs +++ b/server/src/http/context.rs @@ -34,6 +34,7 @@ pub struct PermissionForward { } #[derive(Clone)] +/// Shared application state threaded through all HTTP handlers via Poem's `Data` extractor. pub struct AppContext { pub state: Arc, pub store: Arc, @@ -78,6 +79,7 @@ pub struct AppContext { #[cfg(test)] impl AppContext { + /// Build a minimal `AppContext` for unit tests with an in-memory store. pub fn new_test(project_root: std::path::PathBuf) -> Self { use crate::agents::AgentPool; let state = SessionState::default(); @@ -119,12 +121,15 @@ impl AppContext { } } +/// Alias for `poem::Result` used by OpenAPI handler return types. pub type OpenApiResult = poem::Result; +/// Return a 400 Bad Request error with the given message. pub fn bad_request(message: String) -> poem::Error { poem::Error::from_string(message, StatusCode::BAD_REQUEST) } +/// Return a 404 Not Found error with the given message. pub fn not_found(message: String) -> poem::Error { poem::Error::from_string(message, StatusCode::NOT_FOUND) } diff --git a/server/src/http/io.rs b/server/src/http/io.rs index 7854b2ee..f8743e78 100644 --- a/server/src/http/io.rs +++ b/server/src/http/io.rs @@ -37,6 +37,7 @@ struct ExecShellPayload { pub args: Vec, } +/// OpenAPI endpoint group for filesystem I/O operations (read, write, list, search). pub struct IoApi { pub ctx: Arc, } diff --git a/server/src/http/mcp/mod.rs b/server/src/http/mcp/mod.rs index 1800e033..e836cc6d 100644 --- a/server/src/http/mcp/mod.rs +++ b/server/src/http/mcp/mod.rs @@ -9,14 +9,23 @@ use serde::{Deserialize, Serialize}; use serde_json::{Value, json}; use std::sync::Arc; +/// MCP tools for agent start, stop, wait, list, and inspect. pub mod agent_tools; +/// MCP tools for server logs, CRDT dump, version, and story movement. pub mod diagnostics; +/// MCP tools for git operations scoped to agent worktrees. pub mod git_tools; +/// MCP tools for merge status and merge-to-master operations. pub mod merge_tools; +/// MCP tools for QA request, approve, and reject workflows. pub mod qa_tools; +/// MCP tools for running shell commands and test suites. pub mod shell_tools; +/// MCP tools for pipeline status, story todos, and triage dump. pub mod status_tools; +/// MCP tools for creating, updating, and managing stories and bugs. pub mod story_tools; +/// MCP tools for the project setup wizard. pub mod wizard_tools; mod dispatch; diff --git a/server/src/http/mod.rs b/server/src/http/mod.rs index 12a137d5..398c007b 100644 --- a/server/src/http/mod.rs +++ b/server/src/http/mod.rs @@ -1,26 +1,46 @@ //! HTTP server — module declarations for all REST, MCP, WebSocket, and SSE endpoints. +/// Agent management HTTP endpoints. pub mod agents; +/// Server-sent event stream for real-time agent output. pub mod agents_sse; +/// Anthropic API key management endpoints. pub mod anthropic; +/// Static asset serving (embedded frontend files). pub mod assets; +/// Bot slash-command HTTP endpoint. pub mod bot_command; +/// Bot configuration read/write endpoints. pub mod bot_config; +/// Chat session HTTP endpoints. pub mod chat; +/// Shared application context threaded through handlers. pub mod context; +/// Server-sent event stream for pipeline/watcher events. pub mod events; +/// Node identity endpoint (public key, node ID). pub mod identity; +/// Filesystem I/O HTTP endpoints (read, write, list, search). pub mod io; +/// Model Context Protocol (MCP) HTTP endpoint and tool modules. pub mod mcp; +/// LLM model selection and listing endpoints. pub mod model; +/// OAuth 2.0 PKCE flow endpoints for Anthropic authentication. pub mod oauth; +/// Project settings HTTP endpoints. pub mod settings; #[cfg(test)] pub(crate) mod test_helpers; +/// Workflow helpers for story/bug file operations. pub mod workflow; +/// Gateway-mode HTTP endpoints for multi-project proxy. pub mod gateway; +/// Project open/close/list HTTP endpoints. pub mod project; +/// Setup wizard HTTP endpoints. pub mod wizard; +/// WebSocket handler for real-time frontend communication. pub mod ws; use agents::AgentsApi; @@ -44,26 +64,31 @@ use crate::chat::transport::whatsapp::WhatsAppWebhookContext; const DEFAULT_PORT: u16 = 3001; +/// Parse an optional port string, falling back to the default (3001). pub fn parse_port(value: Option) -> u16 { value .and_then(|v| v.parse::().ok()) .unwrap_or(DEFAULT_PORT) } +/// Read the server port from the `HUSKIES_PORT` env var, or use the default. pub fn resolve_port() -> u16 { parse_port(std::env::var("HUSKIES_PORT").ok()) } +/// Write a `.huskies_port` file so other processes can discover the port. pub fn write_port_file(dir: &Path, port: u16) -> Option { let path = dir.join(".huskies_port"); std::fs::write(&path, port.to_string()).ok()?; Some(path) } +/// Delete the `.huskies_port` file on shutdown. pub fn remove_port_file(path: &Path) { let _ = std::fs::remove_file(path); } +/// Assemble the full Poem route tree (API, WebSocket, MCP, OAuth, assets). pub fn build_routes( ctx: AppContext, whatsapp_ctx: Option>, diff --git a/server/src/http/model.rs b/server/src/http/model.rs index 8059b729..1415f7f1 100644 --- a/server/src/http/model.rs +++ b/server/src/http/model.rs @@ -16,6 +16,7 @@ struct ModelPayload { model: String, } +/// OpenAPI endpoint group for LLM model selection and listing. pub struct ModelApi { pub ctx: Arc, } diff --git a/server/src/http/project.rs b/server/src/http/project.rs index dca8aa6f..069e696a 100644 --- a/server/src/http/project.rs +++ b/server/src/http/project.rs @@ -27,6 +27,7 @@ fn map_project_error(e: ProjectError) -> poem::Error { } } +/// OpenAPI endpoint group for project open, close, and listing operations. pub struct ProjectApi { pub ctx: Arc, } diff --git a/server/src/http/settings.rs b/server/src/http/settings.rs index 9c960f91..a3ada552 100644 --- a/server/src/http/settings.rs +++ b/server/src/http/settings.rs @@ -55,6 +55,7 @@ struct OpenFileResponse { success: bool, } +/// OpenAPI endpoint group for user preferences and editor configuration. pub struct SettingsApi { pub ctx: Arc, } diff --git a/server/src/http/wizard.rs b/server/src/http/wizard.rs index bc573b75..a997d9d1 100644 --- a/server/src/http/wizard.rs +++ b/server/src/http/wizard.rs @@ -68,6 +68,7 @@ fn parse_step(step_str: &str) -> Result { .map_err(|_| not_found(format!("Unknown wizard step: {step_str}"))) } +/// OpenAPI endpoint group for the multi-step project setup wizard. pub struct WizardApi { pub ctx: Arc, } diff --git a/server/src/http/workflow/story_ops/create.rs b/server/src/http/workflow/story_ops/create.rs index cd1626a2..ed19f0b5 100644 --- a/server/src/http/workflow/story_ops/create.rs +++ b/server/src/http/workflow/story_ops/create.rs @@ -6,6 +6,7 @@ use super::super::{ slugify_name, story_stage, write_story_content, }; +/// Write a new story file to the CRDT content store and return the generated story ID. pub fn create_story_file( root: &std::path::Path, name: &str, diff --git a/server/src/http/workflow/story_ops/criterion.rs b/server/src/http/workflow/story_ops/criterion.rs index 1345b328..8a93cd29 100644 --- a/server/src/http/workflow/story_ops/criterion.rs +++ b/server/src/http/workflow/story_ops/criterion.rs @@ -8,6 +8,7 @@ use super::super::{ slugify_name, story_stage, write_story_content, }; +/// Toggle an acceptance criterion checkbox (`- [ ]` → `- [x]`) by its 0-based index among unchecked items. pub fn check_criterion_in_file( project_root: &Path, story_id: &str, diff --git a/server/src/io/fs/files.rs b/server/src/io/fs/files.rs index d717616c..2e8d0873 100644 --- a/server/src/io/fs/files.rs +++ b/server/src/io/fs/files.rs @@ -39,6 +39,7 @@ pub async fn write_file(path: String, content: String, state: &SessionState) -> } #[derive(Serialize, Debug, poem_openapi::Object)] +/// A directory listing entry with its name and kind (file or directory). pub struct FileEntry { pub name: String, pub kind: String, diff --git a/server/src/io/fs/mod.rs b/server/src/io/fs/mod.rs index 14208dea..d7505afe 100644 --- a/server/src/io/fs/mod.rs +++ b/server/src/io/fs/mod.rs @@ -1,8 +1,13 @@ //! Filesystem I/O — module declarations and re-exports for file operations. +/// File read/write/list operations. pub mod files; +/// Path resolution and project-root discovery. pub mod paths; +/// User model-preference storage. pub mod preferences; +/// Project open/close/list lifecycle. pub mod project; +/// `.huskies/` directory scaffolding for new projects. pub mod scaffold; pub use files::{ diff --git a/server/src/io/fs/paths.rs b/server/src/io/fs/paths.rs index 6964fed5..cd9db33e 100644 --- a/server/src/io/fs/paths.rs +++ b/server/src/io/fs/paths.rs @@ -29,6 +29,7 @@ pub fn find_story_kit_root(start: &Path) -> Option { } } +/// Return the current user's home directory as a string. pub fn get_home_directory() -> Result { let home = homedir::my_home() .map_err(|e| format!("Failed to resolve home directory: {e}"))? diff --git a/server/src/io/fs/preferences.rs b/server/src/io/fs/preferences.rs index 811ac91a..8fd52710 100644 --- a/server/src/io/fs/preferences.rs +++ b/server/src/io/fs/preferences.rs @@ -4,6 +4,7 @@ use serde_json::json; const KEY_SELECTED_MODEL: &str = "selected_model"; +/// Read the user's selected LLM model name from the store. pub fn get_model_preference(store: &dyn StoreOps) -> Result, String> { if let Some(model) = store .get(KEY_SELECTED_MODEL) @@ -15,6 +16,7 @@ pub fn get_model_preference(store: &dyn StoreOps) -> Result, Stri Ok(None) } +/// Persist the user's selected LLM model name to the store. pub fn set_model_preference(model: String, store: &dyn StoreOps) -> Result<(), String> { store.set(KEY_SELECTED_MODEL, json!(model)); store.save()?; diff --git a/server/src/io/fs/project.rs b/server/src/io/fs/project.rs index 805c1fea..91ef1015 100644 --- a/server/src/io/fs/project.rs +++ b/server/src/io/fs/project.rs @@ -84,6 +84,7 @@ pub async fn open_project( Ok(path) } +/// Close the active project by clearing the in-memory root and stored path. #[allow(dead_code)] pub fn close_project(state: &SessionState, store: &dyn StoreOps) -> Result<(), String> { { @@ -99,6 +100,7 @@ pub fn close_project(state: &SessionState, store: &dyn StoreOps) -> Result<(), S Ok(()) } +/// Return the active project path, restoring it from the store if needed. #[allow(dead_code)] pub fn get_current_project( state: &SessionState, @@ -133,6 +135,7 @@ pub fn get_current_project( Ok(None) } +/// List all previously-opened project paths from the store. #[allow(dead_code)] pub fn get_known_projects(store: &dyn StoreOps) -> Result, String> { let projects = store @@ -146,6 +149,7 @@ pub fn get_known_projects(store: &dyn StoreOps) -> Result, String> { Ok(projects) } +/// Remove a project path from the known-projects list in the store. #[allow(dead_code)] pub fn forget_known_project(path: String, store: &dyn StoreOps) -> Result<(), String> { let mut known_projects = get_known_projects(store)?; diff --git a/server/src/io/mod.rs b/server/src/io/mod.rs index 1ad15aab..8177f562 100644 --- a/server/src/io/mod.rs +++ b/server/src/io/mod.rs @@ -1,10 +1,17 @@ //! I/O subsystem — filesystem, shell, search, onboarding, and story metadata operations. +/// Filesystem helpers — file/directory read, write, list, path resolution, and project scaffolding. pub mod fs; +/// Onboarding — guides new projects through spec setup and initial configuration. pub mod onboarding; +/// Code search — full-text search across project files using the `ignore` crate. pub mod search; +/// Shell command execution — runs sandboxed commands in the project directory. pub mod shell; +/// Story metadata — parses and serialises front-matter from story files. pub mod story_metadata; #[cfg(test)] pub(crate) mod test_helpers; +/// Filesystem watcher — detects config changes and pipeline file events for hot-reload. pub mod watcher; +/// Project wizard — multi-step state machine for guided project initialisation. pub mod wizard; diff --git a/server/src/io/search.rs b/server/src/io/search.rs index a087ba7f..0ef0130e 100644 --- a/server/src/io/search.rs +++ b/server/src/io/search.rs @@ -7,6 +7,7 @@ use std::fs; use std::path::PathBuf; #[derive(Serialize, Debug, poem_openapi::Object)] +/// A single file that matched a text search, with its match count. pub struct SearchResult { pub path: String, pub matches: usize, diff --git a/server/src/io/shell.rs b/server/src/io/shell.rs index ca0dc36d..c86dfab5 100644 --- a/server/src/io/shell.rs +++ b/server/src/io/shell.rs @@ -4,6 +4,7 @@ use serde::Serialize; use std::path::PathBuf; use std::process::Command; +/// Output captured from a shell command: stdout, stderr, and exit code. #[derive(Serialize, Debug, poem_openapi::Object)] pub struct CommandOutput { pub stdout: String, diff --git a/server/src/io/story_metadata/types.rs b/server/src/io/story_metadata/types.rs index 10a32f59..d6a3f4c7 100644 --- a/server/src/io/story_metadata/types.rs +++ b/server/src/io/story_metadata/types.rs @@ -24,6 +24,7 @@ impl QaMode { } } + /// Return the lowercase string representation of this QA mode. pub fn as_str(&self) -> &'static str { match self { Self::Server => "server", @@ -39,6 +40,7 @@ impl std::fmt::Display for QaMode { } } +/// Parsed YAML front-matter fields from a story markdown file. #[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct StoryMetadata { pub name: Option, @@ -71,6 +73,7 @@ pub struct StoryMetadata { pub mergemaster_attempted: Option, } +/// Errors that can occur when parsing story front-matter metadata. #[derive(Debug, Clone, PartialEq, Eq)] pub enum StoryMetaError { MissingFrontMatter, diff --git a/server/src/llm/mod.rs b/server/src/llm/mod.rs index f9bacdfe..6775c1d0 100644 --- a/server/src/llm/mod.rs +++ b/server/src/llm/mod.rs @@ -1,6 +1,11 @@ //! LLM subsystem — chat orchestration, prompts, OAuth, and provider integrations. +/// Chat session orchestration — manages multi-turn LLM conversations with streaming. pub mod chat; +/// OAuth credential flow for LLM API access (e.g. Anthropic OAuth PKCE). pub mod oauth; +/// System prompt templates for agent and onboarding sessions. pub mod prompts; +/// LLM provider implementations (Anthropic, Claude Code, Ollama). pub mod providers; +/// Core LLM data types: `Message`, `Role`, `ToolCall`, and `ModelProvider`. pub mod types; diff --git a/server/src/llm/prompts.rs b/server/src/llm/prompts.rs index f4d6d57e..ec5b79fa 100644 --- a/server/src/llm/prompts.rs +++ b/server/src/llm/prompts.rs @@ -1,4 +1,6 @@ //! System prompts — static prompt templates for the LLM chat and onboarding flows. + +/// The default system prompt injected at the start of every agent chat session. pub const SYSTEM_PROMPT: &str = r#"You are an AI Agent with direct access to the user's filesystem and development environment. CRITICAL INSTRUCTIONS: @@ -91,6 +93,7 @@ REMEMBER: Remember: You are an autonomous agent that can both explain concepts and take action. Choose appropriately based on the user's request. "#; +/// System prompt override used when a project is newly scaffolded and needs onboarding. pub const ONBOARDING_PROMPT: &str = r#"ONBOARDING MODE ACTIVE — This is a newly scaffolded project. The spec files still contain placeholder content and must be replaced with real project information before any stories can be written. Guide the user through each step below. Ask ONE category of questions at a time — do not overwhelm the user with everything at once. diff --git a/server/src/llm/providers/claude_code/mod.rs b/server/src/llm/providers/claude_code/mod.rs index 38ae1a2b..1e127488 100644 --- a/server/src/llm/providers/claude_code/mod.rs +++ b/server/src/llm/providers/claude_code/mod.rs @@ -36,9 +36,11 @@ mod parse; use events::{handle_stream_event, process_json_event}; +/// Orchestrates Claude Code CLI sessions via a PTY for streaming agent chat. pub struct ClaudeCodeProvider; impl ClaudeCodeProvider { + /// Creates a new `ClaudeCodeProvider`. pub fn new() -> Self { Self } diff --git a/server/src/llm/providers/mod.rs b/server/src/llm/providers/mod.rs index 32c8336a..b3e29c1c 100644 --- a/server/src/llm/providers/mod.rs +++ b/server/src/llm/providers/mod.rs @@ -1,4 +1,7 @@ //! LLM providers — module declarations for Anthropic, Claude Code, and Ollama backends. +/// Anthropic API provider — drives chat completions via the Anthropic Messages API. pub mod anthropic; +/// Claude Code CLI provider — runs `claude` in a PTY and parses structured NDJSON output. pub mod claude_code; +/// Ollama provider — streaming completion client for locally-hosted Ollama models. pub mod ollama; diff --git a/server/src/llm/providers/ollama.rs b/server/src/llm/providers/ollama.rs index cc501d0d..77715a82 100644 --- a/server/src/llm/providers/ollama.rs +++ b/server/src/llm/providers/ollama.rs @@ -7,11 +7,13 @@ use futures::StreamExt; use serde::{Deserialize, Serialize}; use serde_json::Value; +/// Ollama HTTP/streaming client that connects to a local Ollama server. pub struct OllamaProvider { base_url: String, } impl OllamaProvider { + /// Creates a new `OllamaProvider` pointing at the given Ollama server base URL. pub fn new(base_url: String) -> Self { Self { base_url } } diff --git a/server/src/llm/types.rs b/server/src/llm/types.rs index 829a815d..9a7142d3 100644 --- a/server/src/llm/types.rs +++ b/server/src/llm/types.rs @@ -3,6 +3,7 @@ use async_trait::async_trait; use serde::{Deserialize, Serialize}; use std::fmt::Debug; +/// The role of a message participant in an LLM conversation. #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(rename_all = "lowercase")] pub enum Role { @@ -12,6 +13,7 @@ pub enum Role { Tool, } +/// A single message in an LLM conversation, including optional tool call attachments. #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Message { pub role: Role, @@ -24,6 +26,7 @@ pub struct Message { pub tool_call_id: Option, } +/// A tool invocation requested by the LLM, containing the call ID and function details. #[derive(Debug, Serialize, Deserialize, Clone)] pub struct ToolCall { pub id: Option, @@ -32,12 +35,14 @@ pub struct ToolCall { pub kind: String, } +/// The function name and JSON-encoded arguments for a tool call. #[derive(Debug, Serialize, Deserialize, Clone)] pub struct FunctionCall { pub name: String, pub arguments: String, } +/// A tool definition passed to the LLM describing an available function and its schema. #[derive(Debug, Serialize, Deserialize, Clone)] pub struct ToolDefinition { #[serde(rename = "type")] @@ -45,6 +50,7 @@ pub struct ToolDefinition { pub function: ToolFunctionDefinition, } +/// The name, description, and JSON schema for a single tool function. #[derive(Debug, Serialize, Deserialize, Clone)] pub struct ToolFunctionDefinition { pub name: String, @@ -52,6 +58,7 @@ pub struct ToolFunctionDefinition { pub parameters: serde_json::Value, } +/// The response from an LLM completion request, containing text and/or tool calls. #[derive(Debug, Serialize, Deserialize)] pub struct CompletionResponse { pub content: Option, @@ -61,6 +68,7 @@ pub struct CompletionResponse { pub session_id: Option, } +/// Trait for LLM backends; implementations drive chat completions with optional tool use. #[async_trait] #[allow(dead_code)] pub trait ModelProvider: Send + Sync { diff --git a/server/src/log_buffer.rs b/server/src/log_buffer.rs index 2e9b25d5..c1b287ba 100644 --- a/server/src/log_buffer.rs +++ b/server/src/log_buffer.rs @@ -24,6 +24,7 @@ pub enum LogLevel { } impl LogLevel { + /// Return the uppercase string label for this level (`"ERROR"`, `"WARN"`, or `"INFO"`). pub fn as_str(&self) -> &'static str { match self { LogLevel::Error => "ERROR", @@ -75,6 +76,7 @@ impl LogEntry { } } +/// Bounded in-memory ring buffer holding recent log entries and a broadcast channel for live streaming. pub struct LogBuffer { entries: Mutex>, log_file: Mutex>, diff --git a/server/src/main.rs b/server/src/main.rs index 4b385e02..5c4f2c75 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -9,22 +9,32 @@ mod agent_mode; mod agents; mod chat; mod config; +/// CRDT snapshot — serialisation and restore of the full pipeline CRDT state. pub mod crdt_snapshot; +/// CRDT state — in-memory pipeline state machine backed by a distributed CRDT. pub mod crdt_state; +/// CRDT sync — WebSocket-based peer synchronisation for distributed nodes. pub mod crdt_sync; +/// CRDT wire format — on-wire message types for the crdt-sync protocol. pub mod crdt_wire; mod db; +/// Gateway mode — multi-project reverse proxy that fronts multiple project containers. pub mod gateway; mod gateway_relay; mod http; mod io; mod llm; +/// Log buffer — in-memory ring buffer for recent server-side log lines. pub mod log_buffer; +/// Mesh — peer discovery and multi-hop CRDT replication over WebSocket. pub mod mesh; +/// Node identity — Ed25519 keypair generation and stable node ID management. pub mod node_identity; pub(crate) mod pipeline_state; +/// Rebuild — process restart and shutdown coordination. pub mod rebuild; mod service; +/// Services — shared service bundle injected into HTTP handlers and bot tasks. pub mod services; mod startup; mod state; diff --git a/server/src/pipeline_state/events.rs b/server/src/pipeline_state/events.rs index 8c627c13..a13cf096 100644 --- a/server/src/pipeline_state/events.rs +++ b/server/src/pipeline_state/events.rs @@ -21,21 +21,25 @@ pub trait TransitionSubscriber: Send + Sync { fn on_transition(&self, fired: &TransitionFired); } +/// Collects [`TransitionSubscriber`]s and dispatches [`TransitionFired`] events to each. pub struct EventBus { subscribers: Vec>, } impl EventBus { + /// Create an empty event bus with no subscribers. pub fn new() -> Self { Self { subscribers: Vec::new(), } } + /// Register a subscriber to receive all future transition events. pub fn subscribe(&mut self, subscriber: S) { self.subscribers.push(Box::new(subscriber)); } + /// Fire a transition event, calling every registered subscriber in order. pub fn fire(&self, event: TransitionFired) { for sub in &self.subscribers { sub.on_transition(&event); diff --git a/server/src/pipeline_state/subscribers.rs b/server/src/pipeline_state/subscribers.rs index 9acd7eb8..0367695c 100644 --- a/server/src/pipeline_state/subscribers.rs +++ b/server/src/pipeline_state/subscribers.rs @@ -10,6 +10,7 @@ use super::{event_label, stage_dir_name, stage_label}; // These are ready to wire into the event bus but not yet connected to the // actual subsystems. Suppress dead_code until consumers are migrated. +/// Subscriber that logs pipeline transitions to the Matrix bot channel. #[allow(dead_code)] pub struct MatrixBotSubscriber; #[allow(dead_code)] @@ -27,6 +28,7 @@ impl TransitionSubscriber for MatrixBotSubscriber { } } +/// Subscriber that re-renders the filesystem `work/` directory on stage transitions. #[allow(dead_code)] pub struct FileRendererSubscriber; #[allow(dead_code)] @@ -43,6 +45,7 @@ impl TransitionSubscriber for FileRendererSubscriber { } } +/// Subscriber that writes stage updates to the pipeline-items data store. #[allow(dead_code)] pub struct PipelineItemsSubscriber; #[allow(dead_code)] @@ -59,6 +62,7 @@ impl TransitionSubscriber for PipelineItemsSubscriber { } } +/// Subscriber that promotes eligible backlog items when a story completes or is archived. #[allow(dead_code)] pub struct AutoAssignSubscriber; #[allow(dead_code)] @@ -77,6 +81,7 @@ impl TransitionSubscriber for AutoAssignSubscriber { } } +/// Subscriber that broadcasts stage transitions to all connected WebSocket clients. #[allow(dead_code)] pub struct WebUiBroadcastSubscriber; #[allow(dead_code)] diff --git a/server/src/pipeline_state/transition.rs b/server/src/pipeline_state/transition.rs index 8685fc35..e86492d6 100644 --- a/server/src/pipeline_state/transition.rs +++ b/server/src/pipeline_state/transition.rs @@ -51,6 +51,7 @@ pub enum PipelineEvent { // ── Per-node execution events ─────────────────────────────────────────────── +/// Events that drive per-node [`ExecutionState`] transitions (agent lifecycle). #[derive(Debug, Clone, Serialize, Deserialize)] pub enum ExecutionEvent { SpawnRequested { agent: AgentName }, diff --git a/server/src/pipeline_state/types.rs b/server/src/pipeline_state/types.rs index f8c58fb0..59e4f937 100644 --- a/server/src/pipeline_state/types.rs +++ b/server/src/pipeline_state/types.rs @@ -7,18 +7,23 @@ use std::num::NonZeroU32; // ── Newtypes ──────────────────────────────────────────────────────────────── +/// Unique identifier for a pipeline work item (story, bug, spike, or refactor). #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct StoryId(pub String); +/// Git branch name associated with a work item. #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct BranchName(pub String); +/// A Git commit SHA (typically the merge commit written when a story lands on master). #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct GitSha(pub String); +/// The name of the agent process handling a work item on a given node. #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct AgentName(pub String); +/// Ed25519 public key (32 bytes) that uniquely identifies a huskies node in the mesh. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct NodePubkey(pub [u8; 32]); @@ -191,6 +196,7 @@ pub struct PipelineItem { // ── Transition errors ─────────────────────────────────────────────────────── +/// Error returned when a pipeline event is not valid for the current stage. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum TransitionError { InvalidTransition { from_stage: String, event: String }, diff --git a/server/src/rebuild.rs b/server/src/rebuild.rs index c2fafb09..20ea1a25 100644 --- a/server/src/rebuild.rs +++ b/server/src/rebuild.rs @@ -31,6 +31,7 @@ pub struct BotShutdownNotifier { } impl BotShutdownNotifier { + /// Create a notifier that will send shutdown/startup messages via `transport` to the given `channels`. pub fn new(transport: Arc, channels: Vec, bot_name: String) -> Self { Self { transport, diff --git a/server/src/service/agents/mod.rs b/server/src/service/agents/mod.rs index db5280fc..f4fda78b 100644 --- a/server/src/service/agents/mod.rs +++ b/server/src/service/agents/mod.rs @@ -7,7 +7,9 @@ //! //! Conventions: `docs/architecture/service-modules.md` mod io; +/// Agent selection heuristics — pick the best agent for a story. pub mod selection; +/// Token usage tracking and budget enforcement. pub mod token; use crate::agents::AgentInfo; diff --git a/server/src/service/bot_command/mod.rs b/server/src/service/bot_command/mod.rs index b26222b6..89a90dce 100644 --- a/server/src/service/bot_command/mod.rs +++ b/server/src/service/bot_command/mod.rs @@ -11,6 +11,7 @@ //! - `io.rs` — all side-effectful calls (transport handlers, stores, agent pool) pub(super) mod io; +/// Pure argument parsing for bot slash commands. pub mod parse; use crate::agents::AgentPool; diff --git a/server/src/service/common/mod.rs b/server/src/service/common/mod.rs index 8595a336..6a8ae20c 100644 --- a/server/src/service/common/mod.rs +++ b/server/src/service/common/mod.rs @@ -3,4 +3,5 @@ //! All sub-modules here are pure (no I/O, no side effects). Any helper that //! duplicates logic across two or more service modules belongs here; anything //! used by only one service stays in that service. +/// Story/bug/spike ID extraction and formatting helpers. pub mod item_id; diff --git a/server/src/service/diagnostics/mod.rs b/server/src/service/diagnostics/mod.rs index c298ba61..bb32919d 100644 --- a/server/src/service/diagnostics/mod.rs +++ b/server/src/service/diagnostics/mod.rs @@ -6,7 +6,9 @@ //! - `io.rs` — the ONLY place that performs side effects (filesystem reads/writes) //! - `permission.rs` — pure permission-rule generation and wildcard checks +/// Side-effectful diagnostics I/O — log reads, CRDT dumps, filesystem writes. pub mod io; +/// Pure permission-rule generation and wildcard matching. pub mod permission; #[allow(unused_imports)] diff --git a/server/src/service/events/mod.rs b/server/src/service/events/mod.rs index 53057402..b7c2de45 100644 --- a/server/src/service/events/mod.rs +++ b/server/src/service/events/mod.rs @@ -6,6 +6,7 @@ //! //! Conventions: `docs/architecture/service-modules.md` +/// Bounded in-memory event ring buffer for SSE streaming. pub mod buffer; pub(super) mod io; diff --git a/server/src/service/gateway/mod.rs b/server/src/service/gateway/mod.rs index b41a6b23..1c3b3b7e 100644 --- a/server/src/service/gateway/mod.rs +++ b/server/src/service/gateway/mod.rs @@ -7,9 +7,12 @@ //! - `aggregation.rs` — pure cross-project pipeline formatting //! - `polling.rs` — pure notification event formatting +/// Cross-project pipeline status aggregation and formatting. pub mod aggregation; +/// Gateway configuration types and TOML parsing. pub mod config; pub(crate) mod io; +/// Notification event polling for gateway-level broadcasts. pub mod polling; pub use aggregation::format_aggregate_status_compact; diff --git a/server/src/service/git_ops/mod.rs b/server/src/service/git_ops/mod.rs index 049104f6..21e73c06 100644 --- a/server/src/service/git_ops/mod.rs +++ b/server/src/service/git_ops/mod.rs @@ -7,8 +7,11 @@ //! - `path_guard.rs` — pure path-prefix safety checks //! - `porcelain.rs` — pure git porcelain output parsers +/// Side-effectful git command execution (add, commit, diff, log, status). pub mod io; +/// Pure worktree path-prefix safety checks. pub mod path_guard; +/// Pure git porcelain output parsers. pub mod porcelain; #[allow(unused_imports)] diff --git a/server/src/service/merge/mod.rs b/server/src/service/merge/mod.rs index 1789f083..3171969c 100644 --- a/server/src/service/merge/mod.rs +++ b/server/src/service/merge/mod.rs @@ -6,7 +6,9 @@ //! - `io.rs` — the ONLY place that performs side effects //! - `status.rs` — pure merge-status message formatting +/// Side-effectful merge I/O — rebase, cherry-pick, and branch operations. pub mod io; +/// Pure merge-status message formatting. pub mod status; #[allow(unused_imports)] diff --git a/server/src/service/mod.rs b/server/src/service/mod.rs index 86eaba72..f38427ac 100644 --- a/server/src/service/mod.rs +++ b/server/src/service/mod.rs @@ -5,25 +5,47 @@ //! - `mod.rs` orchestrates and owns the typed `Error` type //! - `io.rs` is the only file that performs side effects //! - Topic-named pure files contain branching logic with no I/O +/// Agent management — start, stop, inspect, and list agents. pub mod agents; +/// Anthropic API key storage and model listing. pub mod anthropic; +/// Bot command dispatch — parses and executes slash commands. pub mod bot_command; +/// Shared pure helpers used across service modules. pub mod common; +/// Diagnostics — server logs, CRDT dump, and permission management. pub mod diagnostics; +/// Pipeline event buffer for SSE streaming. pub mod events; +/// File I/O — path validation, read, write, and listing. pub mod file_io; +/// Gateway — multi-project proxy domain logic. pub mod gateway; +/// Git operations — worktree-scoped git commands. pub mod git_ops; +/// Merge — rebase agent work onto master and validate. pub mod merge; +/// Notifications — fan-out pipeline events to chat transports. pub mod notifications; +/// OAuth 2.0 PKCE flow for Anthropic authentication. pub mod oauth; +/// Pipeline status aggregation helpers. pub mod pipeline; +/// Project open/close/list domain logic. pub mod project; +/// QA — request, approve, and reject code reviews. pub mod qa; +/// Project settings read/write and validation. pub mod settings; +/// Shell command safety, sandboxing, and output helpers. pub mod shell; +/// Status broadcaster — unified event fan-out to all consumers. pub mod status; +/// Story CRUD — create, update, move, and manage work items. pub mod story; +/// Timer — deferred agent start via one-shot timers. pub mod timer; +/// Wizard — multi-step project setup domain logic. pub mod wizard; +/// WebSocket — real-time pipeline updates and permission prompts. pub mod ws; diff --git a/server/src/service/oauth/mod.rs b/server/src/service/oauth/mod.rs index dba52c01..d8c11458 100644 --- a/server/src/service/oauth/mod.rs +++ b/server/src/service/oauth/mod.rs @@ -7,8 +7,10 @@ //! - `pkce.rs` — pure PKCE helpers: generation, challenge, encoding //! - `flow.rs` — pure flow types and token-expiry decision logic +/// Pure OAuth flow types and token-expiry decision logic. pub mod flow; pub(super) mod io; +/// Pure PKCE helpers — code verifier generation, challenge derivation, base64url encoding. pub mod pkce; pub use flow::AccountInfo; diff --git a/server/src/service/project/mod.rs b/server/src/service/project/mod.rs index cdad1a60..5d21796e 100644 --- a/server/src/service/project/mod.rs +++ b/server/src/service/project/mod.rs @@ -7,6 +7,7 @@ //! Conventions: `docs/architecture/service-modules.md` pub(super) mod io; +/// Pure project selection and path-matching logic. pub mod selection; use crate::state::SessionState; diff --git a/server/src/service/qa/mod.rs b/server/src/service/qa/mod.rs index da4aa375..a8f40c07 100644 --- a/server/src/service/qa/mod.rs +++ b/server/src/service/qa/mod.rs @@ -6,7 +6,9 @@ //! - `io.rs` — the ONLY place that performs side effects (git, TCP, process) //! - `lifecycle.rs` — pure QA routing decisions (spike vs. normal story) +/// Side-effectful QA I/O — git operations, port scanning, branch merging. pub mod io; +/// Pure QA routing decisions (spike vs. normal story). pub mod lifecycle; pub use io::{find_free_port, merge_spike_branch_to_master}; diff --git a/server/src/service/settings/mod.rs b/server/src/service/settings/mod.rs index 123c86b3..984e05f3 100644 --- a/server/src/service/settings/mod.rs +++ b/server/src/service/settings/mod.rs @@ -9,7 +9,9 @@ //! - `validate.rs` — pure validation: [`validate_project_settings`] pub(super) mod io; +/// Pure types: `ProjectSettings`, TOML serialization, config merging. pub mod project; +/// Pure project-settings validation rules. pub mod validate; pub use project::{ProjectSettings, merge_settings_into_toml, settings_from_config}; diff --git a/server/src/service/shell/mod.rs b/server/src/service/shell/mod.rs index 50b286b1..49a8ed3d 100644 --- a/server/src/service/shell/mod.rs +++ b/server/src/service/shell/mod.rs @@ -6,7 +6,9 @@ //! - `io.rs` — the ONLY place that performs side effects (filesystem checks) //! - `path_guard.rs` — pure command-safety checks and output utilities +/// Side-effectful shell I/O — filesystem permission checks. pub mod io; +/// Pure command-safety checks, blocked-binary lists, and output truncation. pub mod path_guard; #[allow(unused_imports)] diff --git a/server/src/service/status/mod.rs b/server/src/service/status/mod.rs index 59bdc008..98f20c6f 100644 --- a/server/src/service/status/mod.rs +++ b/server/src/service/status/mod.rs @@ -23,7 +23,9 @@ //! - Story 643 (Web UI): calls `subscribe()` once at startup. //! - Story 644 (chat transports): calls `subscribe()` once per transport. +/// Bounded ring buffer for recent status events. pub mod buffer; +/// Pure status-event to human-readable string formatting. pub mod format; use chrono::{DateTime, Utc}; diff --git a/server/src/service/story/mod.rs b/server/src/service/story/mod.rs index 7872b2bb..32d52322 100644 --- a/server/src/service/story/mod.rs +++ b/server/src/service/story/mod.rs @@ -31,10 +31,15 @@ //! - `pipeline_items` row — updated on stage transitions and item creation/deletion //! - `content_store` entry — updated on story content changes, deleted on purge/delete +/// Pure criterion parsing, checkbox toggling, and validation. pub mod criteria; +/// Pure front-matter field validation (stage names, agent assignments). pub mod front_matter; +/// Side-effectful story file I/O — read, write, move, and delete. pub mod io; +/// Pure story-ID helpers and lifecycle state transitions. pub mod lifecycle; +/// Pure story content validation rules. pub mod validation; pub use criteria::parse_test_cases; diff --git a/server/src/service/wizard/mod.rs b/server/src/service/wizard/mod.rs index f5d4694b..7349adfa 100644 --- a/server/src/service/wizard/mod.rs +++ b/server/src/service/wizard/mod.rs @@ -7,6 +7,7 @@ //! step classification — all unit-testable without tempdirs or an async runtime pub(crate) mod io; +/// Pure wizard state-machine helpers — bare-project detection, step classification. pub mod state_machine; use crate::io::wizard::{StepStatus, WizardState, WizardStep, format_wizard_state}; diff --git a/server/src/service/ws/message/mod.rs b/server/src/service/ws/message/mod.rs index 0bb06ed1..be707eeb 100644 --- a/server/src/service/ws/message/mod.rs +++ b/server/src/service/ws/message/mod.rs @@ -4,8 +4,11 @@ //! Conversions from domain events to WsResponse live here too. //! All logic is pure data transformation; I/O lives in `io.rs`. +/// Conversions from domain events to `WsResponse` frames. pub mod convert; +/// Client-to-server `WsRequest` message definitions. pub mod request; +/// Server-to-client `WsResponse` message definitions. pub mod response; pub use convert::{needs_pipeline_refresh, wizard_steps_to_info}; diff --git a/server/src/service/ws/mod.rs b/server/src/service/ws/mod.rs index 7d10d244..0eef977d 100644 --- a/server/src/service/ws/mod.rs +++ b/server/src/service/ws/mod.rs @@ -9,9 +9,12 @@ //! - `dispatch.rs` — pure request routing and permission resolution //! - `error.rs` — typed error enum +/// Pure request routing and permission resolution. pub mod dispatch; +/// Typed WebSocket error enum. pub mod error; pub(super) mod io; +/// Pure WebSocket message types and domain-event conversions. pub mod message; pub use dispatch::{ diff --git a/server/src/state.rs b/server/src/state.rs index 61778e84..6823329f 100644 --- a/server/src/state.rs +++ b/server/src/state.rs @@ -3,6 +3,7 @@ use std::path::PathBuf; use std::sync::Mutex; use tokio::sync::watch; +/// Global server session state: the open project root and a cancellation signal. pub struct SessionState { pub project_root: Mutex>, pub cancel_tx: watch::Sender, @@ -21,6 +22,7 @@ impl Default for SessionState { } impl SessionState { + /// Return the currently open project root, or an error if no project is open. pub fn get_project_root(&self) -> Result { let root_guard = self.project_root.lock().map_err(|e| e.to_string())?; let root = root_guard.as_ref().ok_or_else(|| { diff --git a/server/src/store.rs b/server/src/store.rs index fcb44a6c..43e4fd88 100644 --- a/server/src/store.rs +++ b/server/src/store.rs @@ -5,6 +5,7 @@ use std::fs; use std::path::{Path, PathBuf}; use std::sync::Mutex; +/// Trait for a simple key-value store that can get, set, delete, and persist entries. pub trait StoreOps: Send + Sync { fn get(&self, key: &str) -> Option; fn set(&self, key: &str, value: Value); @@ -12,12 +13,14 @@ pub trait StoreOps: Send + Sync { fn save(&self) -> Result<(), String>; } +/// A JSON-backed file store that persists key-value data to a single file on disk. pub struct JsonFileStore { path: PathBuf, data: Mutex>, } impl JsonFileStore { + /// Create a new store backed by `path`, loading existing data if the file is present. pub fn new(path: PathBuf) -> Result { let data = if path.exists() { let content = @@ -38,10 +41,12 @@ impl JsonFileStore { }) } + /// Convenience constructor accepting any path type; delegates to [`Self::new`]. pub fn from_path>(path: P) -> Result { Self::new(path.as_ref().to_path_buf()) } + /// Return the path to the backing JSON file. #[allow(dead_code)] pub fn path(&self) -> &Path { &self.path diff --git a/server/src/workflow.rs b/server/src/workflow.rs index f084171e..85ee1de1 100644 --- a/server/src/workflow.rs +++ b/server/src/workflow.rs @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; +/// Whether an individual test case passed or failed. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum TestStatus { @@ -10,6 +11,7 @@ pub enum TestStatus { Fail, } +/// The name, status, and optional details for a single test case execution. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct TestCaseResult { pub name: String, @@ -22,6 +24,7 @@ struct TestRunSummary { failed: usize, } +/// The outcome of evaluating whether a story is ready for acceptance. #[derive(Debug, Clone, PartialEq, Eq)] pub struct AcceptanceDecision { pub can_accept: bool, @@ -29,12 +32,14 @@ pub struct AcceptanceDecision { pub warning: Option, } +/// Collected unit and integration test results recorded for a single story. #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct StoryTestResults { pub unit: Vec, pub integration: Vec, } +/// Server-wide in-memory workflow state: test results and coverage reports keyed by story ID. #[derive(Debug, Clone, Default)] pub struct WorkflowState { pub results: HashMap, @@ -42,6 +47,7 @@ pub struct WorkflowState { } impl WorkflowState { + /// Record unit and integration test results for a story, rejecting batches with more than one failure. pub fn record_test_results_validated( &mut self, story_id: String, diff --git a/server/src/worktree/mod.rs b/server/src/worktree/mod.rs index a9817536..5e6bcd52 100644 --- a/server/src/worktree/mod.rs +++ b/server/src/worktree/mod.rs @@ -12,6 +12,7 @@ pub use remove::remove_worktree_by_story_id; pub use sweep::sweep_orphaned_worktrees; #[derive(Debug, Clone)] +/// Details about a newly created worktree: path, branch, and base branch. pub struct WorktreeInfo { pub path: PathBuf, pub branch: String, @@ -19,6 +20,7 @@ pub struct WorktreeInfo { } #[derive(Debug, Clone)] +/// A discovered worktree on disk: its story ID and filesystem path. pub struct WorktreeListEntry { pub story_id: String, pub path: PathBuf,