pub mod backend;
pub mod clean;
pub mod components;
pub mod config;
pub mod doctor;
pub mod graph;
pub mod init;
pub mod mcp;
pub mod search;
pub mod status;
pub mod update;
pub mod workspace;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use anyhow::{Context, Result};
use codeprysm_backend::{LocalBackend, WorkspaceRegistry};
use codeprysm_config::{ConfigLoader, PrismConfig};
use codeprysm_search::embeddings::{
AzureMLAuth, AzureMLConfig, EmbeddingConfig as SearchEmbeddingConfig, OpenAIConfig,
};
use crate::GlobalOptions;
pub async fn resolve_workspace(global: &GlobalOptions) -> Result<PathBuf> {
if let Some(ref ws) = global.workspace {
let path = PathBuf::from(ws);
if path.exists() {
return Ok(path.canonicalize()?);
}
let registry = WorkspaceRegistry::new()
.await
.context("Failed to load workspace registry")?;
if let Some(path) = registry.get(ws).await {
return Ok(path);
}
anyhow::bail!(
"Workspace '{}' not found (not a valid path or registered name)",
ws
);
}
std::env::current_dir().context("Failed to get current directory")
}
pub fn load_config(global: &GlobalOptions, workspace: &Path) -> Result<PrismConfig> {
let mut loader = ConfigLoader::new();
if let Some(ref config_path) = global.config {
if let Some(parent) = config_path.parent() {
return loader
.load_local(parent)
.context("Failed to load config file")?
.ok_or_else(|| {
anyhow::anyhow!("Config file not found: {}", config_path.display())
});
}
}
loader
.load(workspace, None)
.context("Failed to load configuration")
}
pub async fn create_backend(global: &GlobalOptions) -> Result<Arc<LocalBackend>> {
let workspace = resolve_workspace(global).await?;
let mut config = load_config(global, &workspace)?;
let overrides = global.to_config_overrides();
config.apply_overrides(&overrides);
let backend = LocalBackend::new(&config, &workspace)
.await
.context("Failed to create backend")?;
Ok(Arc::new(backend))
}
#[allow(dead_code)]
pub fn print_result<T: std::fmt::Display>(result: T, quiet: bool) {
if !quiet {
println!("{}", result);
}
}
#[allow(dead_code)]
pub fn print_error(message: &str) {
eprintln!("error: {}", message);
}
#[allow(dead_code)]
pub fn print_warning(message: &str) {
eprintln!("warning: {}", message);
}
pub fn print_info(message: &str, quiet: bool) {
if !quiet {
eprintln!("{}", message);
}
}
pub fn to_search_embedding_config(config: &PrismConfig) -> SearchEmbeddingConfig {
use codeprysm_config::EmbeddingProviderType;
match config.embedding.provider {
EmbeddingProviderType::Local => SearchEmbeddingConfig::local(),
EmbeddingProviderType::AzureMl => {
if let Some(ref azure) = config.embedding.azure_ml {
let semantic_auth = if let Some(ref env_var) = azure.semantic_auth_key_env {
AzureMLAuth::ApiKeyEnv(env_var.clone())
} else if let Some(ref env_var) = azure.auth_key_env {
AzureMLAuth::ApiKeyEnv(env_var.clone())
} else {
AzureMLAuth::ApiKeyEnv("CODEPRYSM_AZURE_ML_SEMANTIC_API_KEY".to_string())
};
let code_auth = azure
.code_auth_key_env
.as_ref()
.map(|env_var| AzureMLAuth::ApiKeyEnv(env_var.clone()));
let azure_config = AzureMLConfig {
semantic_endpoint: azure.semantic_endpoint.clone(),
code_endpoint: azure.code_endpoint.clone(),
semantic_auth,
code_auth,
timeout_secs: azure.timeout_secs,
max_retries: azure.max_retries,
};
SearchEmbeddingConfig::azure_ml_with_config(azure_config)
} else {
SearchEmbeddingConfig::azure_ml()
}
}
EmbeddingProviderType::Openai => {
if let Some(ref openai) = config.embedding.openai {
let api_key = openai
.api_key_env
.as_ref()
.and_then(|env_var| std::env::var(env_var).ok());
let openai_config = OpenAIConfig {
base_url: openai.url.clone(),
api_key,
semantic_model: openai.semantic_model.clone(),
code_model: openai.code_model.clone(),
timeout_secs: openai.timeout_secs,
max_retries: openai.max_retries,
azure_mode: openai.azure_mode,
};
SearchEmbeddingConfig::openai_with_config(openai_config)
} else {
SearchEmbeddingConfig::openai()
}
}
}
}