Initial scaffold: GyanDoot v2.0 in Rust
Full Cargo workspace with 11 crates: - gyandoot-core: Shared types, config, error types - gyandoot-agent: Agent loop, tool execution, context compression - gyandoot-providers: LLM provider abstraction (OpenAI, Anthropic, Ollama) - gyandoot-memory: MemPalace persistent memory system - gyandoot-platform: Platform adapters (Telegram, Discord, Webhook, CLI) - gyandoot-security: Credential vault, sanitizer, threat detector - gyandoot-kanban: Task decomposition, swarm orchestration, diagnostics - gyandoot-subagents: Sub-agent spawning and orchestration - gyandoot-skills: Skills discovery, loading, preprocessing, bundles - gyandoot-profile: Multi-agent profile manager - gyandoot-gateway: Gateway sessions, routing, access control Plus: CLI entry point with clap, cross-platform installer script, KANBAN.md, .gnpl/AGENTS.md Workspace compiles clean: cargo check passes with 0 errors.
This commit is contained in:
288
src/main.rs
Normal file
288
src/main.rs
Normal file
@@ -0,0 +1,288 @@
|
||||
//! GyanDoot v2.0 — AI Agent Platform CLI Entry Point
|
||||
//!
|
||||
//! This binary provides the command-line interface for configuring, running,
|
||||
//! and managing GyanDoot agents across multiple platforms.
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
/// GyanDoot v2.0 — AI Agent Platform
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(name = "gyandoot", version, about, long_about = None)]
|
||||
struct Cli {
|
||||
/// Path to the config file (default: ~/.config/gyandoot/config.toml)
|
||||
#[arg(short = 'c', long = "config", env = "GYANDOOT_CONFIG")]
|
||||
config: Option<PathBuf>,
|
||||
|
||||
/// Profile name to use
|
||||
#[arg(short = 'P', long = "profile", default_value = "default")]
|
||||
profile: String,
|
||||
|
||||
/// Log level filter (e.g., info, debug, gyandoot=debug)
|
||||
#[arg(short = 'l', long = "log", default_value = "info", env = "GYANDOOT_LOG")]
|
||||
log_filter: String,
|
||||
|
||||
#[command(subcommand)]
|
||||
command: Option<Commands>,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum Commands {
|
||||
/// Run the agent interactively
|
||||
Run {
|
||||
/// Platform to run on (cli, telegram, discord)
|
||||
#[arg(default_value = "cli")]
|
||||
platform: String,
|
||||
/// Initial prompt or task description
|
||||
prompt: Option<String>,
|
||||
},
|
||||
/// Start the gateway server (handles multi-platform sessions)
|
||||
Serve {
|
||||
/// Host to bind the gateway server
|
||||
#[arg(long, default_value = "127.0.0.1")]
|
||||
host: String,
|
||||
/// Port for the gateway server
|
||||
#[arg(long, default_value_t = 8777)]
|
||||
port: u16,
|
||||
},
|
||||
/// Initialize a default config file
|
||||
Init,
|
||||
/// List available profiles
|
||||
Profiles,
|
||||
/// Manage skills
|
||||
#[command(name = "skills")]
|
||||
Skills {
|
||||
#[command(subcommand)]
|
||||
action: SkillsAction,
|
||||
},
|
||||
/// Manage memory (MemPalace)
|
||||
#[command(name = "memory")]
|
||||
Memory {
|
||||
#[command(subcommand)]
|
||||
action: MemoryAction,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum SkillsAction {
|
||||
/// List installed skills
|
||||
List,
|
||||
/// Install a skill from path or registry
|
||||
Install { source: String },
|
||||
/// Remove a skill
|
||||
Remove { name: String },
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum MemoryAction {
|
||||
/// Show memory status
|
||||
Status,
|
||||
/// Query memory for content
|
||||
Query { query: String },
|
||||
/// Export memory to a file
|
||||
Export { path: PathBuf },
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let cli = Cli::parse();
|
||||
|
||||
// Initialize tracing subscriber
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(EnvFilter::new(&cli.log_filter))
|
||||
.with_target(true)
|
||||
.init();
|
||||
|
||||
tracing::debug!("GyanDoot v2.0 starting (profile: {})", cli.profile);
|
||||
tracing::debug!("Config path: {:?}", cli.config);
|
||||
|
||||
// Resolve config dir
|
||||
let _config_dir = cli.config.unwrap_or_else(default_config_dir);
|
||||
tracing::debug!("Using config dir: {}", _config_dir.display());
|
||||
|
||||
match cli.command {
|
||||
Some(Commands::Run { platform, prompt }) => {
|
||||
cmd_run(&cli.profile, &platform, prompt.as_deref()).await?;
|
||||
}
|
||||
Some(Commands::Serve { host, port }) => {
|
||||
cmd_serve(&cli.profile, &host, port).await?;
|
||||
}
|
||||
Some(Commands::Init) => {
|
||||
cmd_init().await?;
|
||||
}
|
||||
Some(Commands::Profiles) => {
|
||||
cmd_profiles().await?;
|
||||
}
|
||||
Some(Commands::Skills { action }) => {
|
||||
cmd_skills(action).await?;
|
||||
}
|
||||
Some(Commands::Memory { action }) => {
|
||||
cmd_memory(action).await?;
|
||||
}
|
||||
None => {
|
||||
// Default: run interactive CLI mode
|
||||
cmd_run(&cli.profile, "cli", None).await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the default config directory: ~/.config/gyandoot/
|
||||
fn default_config_dir() -> PathBuf {
|
||||
let home = dirs::home_dir().expect("Cannot determine home directory");
|
||||
home.join(".config").join("gyandoot")
|
||||
}
|
||||
|
||||
/// Run the agent in the given platform mode
|
||||
async fn cmd_run(profile_name: &str, platform: &str, prompt: Option<&str>) -> anyhow::Result<()> {
|
||||
tracing::info!("Running agent (profile={}, platform={})", profile_name, platform);
|
||||
|
||||
// Load config via resolver
|
||||
let resolver = gyandoot_profile::ConfigResolver::default();
|
||||
let _resolved = resolver.resolve();
|
||||
|
||||
// Initialize the agent loop using gyandoot-core config
|
||||
let config = gyandoot_core::config::AgentConfig::default();
|
||||
let agent = gyandoot_agent::agent_loop::AgentLoop::new(config);
|
||||
|
||||
if let Some(p) = prompt {
|
||||
tracing::info!("Starting with prompt: {}", p);
|
||||
}
|
||||
|
||||
agent.run().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Start the gateway server for multi-platform sessions
|
||||
async fn cmd_serve(profile_name: &str, host: &str, port: u16) -> anyhow::Result<()> {
|
||||
tracing::info!(
|
||||
"Starting gateway server (profile={}, bind={}:{})",
|
||||
profile_name, host, port
|
||||
);
|
||||
|
||||
let gateway = gyandoot_gateway::GatewayRunner::new();
|
||||
gateway.start().await?;
|
||||
tracing::info!("Gateway running on {}:{} — press Ctrl+C to stop", host, port);
|
||||
|
||||
// Keep running until signal
|
||||
tokio::signal::ctrl_c().await?;
|
||||
gateway.stop().await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Initialize default config files
|
||||
async fn cmd_init() -> anyhow::Result<()> {
|
||||
let config_dir = default_config_dir();
|
||||
tracing::info!("Initializing config in {}", config_dir.display());
|
||||
|
||||
std::fs::create_dir_all(&config_dir)?;
|
||||
let config_path = config_dir.join("config.toml");
|
||||
|
||||
if config_path.exists() {
|
||||
tracing::warn!("Config already exists at {}", config_path.display());
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let default_config = r#"
|
||||
[agent]
|
||||
name = "gyandoot"
|
||||
model = "gpt-4o"
|
||||
max_tokens = 4096
|
||||
temperature = 0.7
|
||||
system_prompt = "You are GyanDoot, an AI Agent Platform."
|
||||
|
||||
[providers]
|
||||
default = "openai"
|
||||
|
||||
[providers.openai]
|
||||
api_key = ""
|
||||
model = "gpt-4o"
|
||||
|
||||
[platform]
|
||||
default = "cli"
|
||||
|
||||
[memory]
|
||||
backend = "local"
|
||||
"#;
|
||||
|
||||
std::fs::write(&config_path, default_config.trim())?;
|
||||
tracing::info!("Created default config at {}", config_path.display());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// List available profiles
|
||||
async fn cmd_profiles() -> anyhow::Result<()> {
|
||||
let resolver = gyandoot_profile::ConfigResolver::default();
|
||||
let profiles_dir = resolver.profiles_dir();
|
||||
|
||||
if profiles_dir.exists() {
|
||||
let mut entries: Vec<_> = std::fs::read_dir(&profiles_dir)?
|
||||
.filter_map(|e| e.ok())
|
||||
.filter(|e| e.path().is_dir())
|
||||
.map(|e| e.file_name().to_string_lossy().to_string())
|
||||
.collect();
|
||||
entries.sort();
|
||||
|
||||
if entries.is_empty() {
|
||||
println!("No profiles found. Use 'gyandoot init' to create one.");
|
||||
} else {
|
||||
println!("Available profiles:");
|
||||
for p in &entries {
|
||||
println!(" - {}", p);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("No profiles found. Use 'gyandoot init' to create one.");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Handle skill management subcommands
|
||||
async fn cmd_skills(action: SkillsAction) -> anyhow::Result<()> {
|
||||
match action {
|
||||
SkillsAction::List => {
|
||||
let mut manager = gyandoot_skills::SkillsManager::new();
|
||||
let skills = manager.scan();
|
||||
if skills.is_empty() {
|
||||
println!("No skills installed.");
|
||||
} else {
|
||||
println!("Installed skills:");
|
||||
for s in &skills {
|
||||
println!(" - {} ({:?})", s.name, s.trust);
|
||||
}
|
||||
}
|
||||
}
|
||||
SkillsAction::Install { source } => {
|
||||
tracing::info!("Skill install from {} (placeholder — integrate skill hub)", source);
|
||||
}
|
||||
SkillsAction::Remove { name } => {
|
||||
tracing::info!("Skill remove: {} (placeholder)", name);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Handle memory management subcommands
|
||||
async fn cmd_memory(action: MemoryAction) -> anyhow::Result<()> {
|
||||
let palace = gyandoot_memory::palace::MemPalace::new();
|
||||
match action {
|
||||
MemoryAction::Status => {
|
||||
#[allow(unused_variables)]
|
||||
let status_msg = format!("Memory: initialized ({})", "in-memory");
|
||||
println!("{}", status_msg);
|
||||
}
|
||||
MemoryAction::Query { query } => {
|
||||
println!("Memory query for: {}", query);
|
||||
#[allow(unused_variables)]
|
||||
let _results = palace.query(&query, 10);
|
||||
println!(" (full memory query not yet implemented in CLI)");
|
||||
}
|
||||
MemoryAction::Export { path } => {
|
||||
tracing::info!("Exporting memory to {}", path.display());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user