use std::path::PathBuf;
use anyhow::{Context, Result};
use clap::{Args, Subcommand};
use codeprysm_backend::WorkspaceRegistry;
use crate::GlobalOptions;
#[derive(Subcommand, Debug)]
pub enum WorkspaceCommand {
List(ListArgs),
Add(AddArgs),
Remove(RemoveArgs),
Use(UseArgs),
Discover(DiscoverArgs),
}
#[derive(Args, Debug)]
pub struct ListArgs {
#[arg(long)]
json: bool,
}
#[derive(Args, Debug)]
pub struct AddArgs {
name: String,
path: PathBuf,
}
#[derive(Args, Debug)]
pub struct RemoveArgs {
name: String,
}
#[derive(Args, Debug)]
pub struct UseArgs {
name: String,
}
#[derive(Args, Debug)]
pub struct DiscoverArgs {
#[arg(default_value = ".")]
root: PathBuf,
#[arg(long, short = 'd', default_value = "3")]
depth: usize,
#[arg(long)]
prefix: Option<String>,
#[arg(long)]
register: bool,
}
pub async fn execute(cmd: WorkspaceCommand, global: GlobalOptions) -> Result<()> {
let registry = WorkspaceRegistry::new()
.await
.context("Failed to load workspace registry")?;
match cmd {
WorkspaceCommand::List(args) => execute_list(®istry, args, global).await,
WorkspaceCommand::Add(args) => execute_add(®istry, args, global).await,
WorkspaceCommand::Remove(args) => execute_remove(®istry, args, global).await,
WorkspaceCommand::Use(args) => execute_use(®istry, args, global).await,
WorkspaceCommand::Discover(args) => execute_discover(®istry, args, global).await,
}
}
async fn execute_list(
registry: &WorkspaceRegistry,
args: ListArgs,
global: GlobalOptions,
) -> Result<()> {
let workspaces = registry.list().await;
if workspaces.is_empty() {
if !global.quiet {
println!("No workspaces registered.");
println!("\nTo register a workspace:");
println!(" codeprysm workspace add <name> <path>");
println!("\nTo discover workspaces:");
println!(" codeprysm workspace discover --register");
}
return Ok(());
}
if args.json {
let json: Vec<_> = workspaces
.iter()
.map(|w| {
serde_json::json!({
"name": w.name,
"path": w.path,
"has_graph": w.has_graph,
"has_index": w.has_index,
"is_active": w.is_active,
})
})
.collect();
println!("{}", serde_json::to_string_pretty(&json)?);
} else {
if !global.quiet {
println!("Registered workspaces:\n");
}
for ws in &workspaces {
let active = if ws.is_active { " *" } else { "" };
let status = if ws.has_graph {
if ws.has_index {
"[indexed]"
} else {
"[graph only]"
}
} else {
"[no graph]"
};
println!(" {}{} {} - {}", ws.name, active, status, ws.path.display());
}
if !global.quiet {
let active = registry.active().await;
if let Some(name) = active {
println!("\n * = active workspace ({})", name);
} else {
println!("\n No active workspace set. Use 'codeprysm workspace use <name>'");
}
}
}
Ok(())
}
async fn execute_add(
registry: &WorkspaceRegistry,
args: AddArgs,
global: GlobalOptions,
) -> Result<()> {
let path = registry
.register(&args.name, &args.path)
.await
.context("Failed to register workspace")?;
if !global.quiet {
println!("Registered workspace '{}' at {}", args.name, path.display());
println!("\nTo initialize the graph:");
println!(" prism -w {} init", args.name);
}
Ok(())
}
async fn execute_remove(
registry: &WorkspaceRegistry,
args: RemoveArgs,
global: GlobalOptions,
) -> Result<()> {
let removed = registry
.unregister(&args.name)
.await
.context("Failed to unregister workspace")?;
if removed {
if !global.quiet {
println!("Removed workspace '{}'", args.name);
}
} else {
anyhow::bail!("Workspace '{}' not found", args.name);
}
Ok(())
}
async fn execute_use(
registry: &WorkspaceRegistry,
args: UseArgs,
global: GlobalOptions,
) -> Result<()> {
registry
.set_active(&args.name)
.await
.context("Failed to set active workspace")?;
if !global.quiet {
println!("Active workspace set to '{}'", args.name);
}
Ok(())
}
async fn execute_discover(
registry: &WorkspaceRegistry,
args: DiscoverArgs,
global: GlobalOptions,
) -> Result<()> {
let root = if args.root.is_absolute() {
args.root.clone()
} else {
std::env::current_dir()?.join(&args.root)
};
let root = root.canonicalize().context("Failed to resolve root path")?;
if !global.quiet {
println!("Discovering workspaces under {}...\n", root.display());
}
let discovered = registry
.discover(&root, args.depth)
.await
.context("Failed to discover workspaces")?;
if discovered.is_empty() {
if !global.quiet {
println!("No workspaces found.");
println!("\nWorkspaces are detected by the presence of .codeprysm/manifest.json");
println!("Initialize a workspace with: codeprysm init <path>");
}
return Ok(());
}
if !global.quiet {
println!("Found {} workspaces:\n", discovered.len());
}
for path in &discovered {
let name = path
.file_name()
.and_then(|n| n.to_str())
.unwrap_or("unknown");
let full_name = if let Some(ref prefix) = args.prefix {
format!("{}/{}", prefix, name)
} else {
name.to_string()
};
println!(" {} - {}", full_name, path.display());
}
if args.register {
if !global.quiet {
println!("\nRegistering discovered workspaces...");
}
let count = registry
.register_discovered(&discovered, args.prefix.as_deref())
.await
.context("Failed to register workspaces")?;
if !global.quiet {
println!("Registered {} workspaces", count);
}
} else if !global.quiet {
println!("\nTo register these workspaces, run:");
println!(" codeprysm workspace discover --register");
}
Ok(())
}