diff --git a/.beans/claudbg-x45o--sessions-list-scope-to-current-project-by-default.md b/.beans/claudbg-x45o--sessions-list-scope-to-current-project-by-default.md index 27bbabf..eae8649 100644 --- a/.beans/claudbg-x45o--sessions-list-scope-to-current-project-by-default.md +++ b/.beans/claudbg-x45o--sessions-list-scope-to-current-project-by-default.md @@ -1,10 +1,18 @@ --- # claudbg-x45o title: 'sessions list: scope to current project by default with --scope flag' -status: todo +status: completed type: feature +priority: normal created_at: 2026-03-31T23:44:50Z -updated_at: 2026-03-31T23:44:50Z +updated_at: 2026-04-01T05:58:09Z --- When run inside a project directory, `claudbg sessions` should only list sessions for that project (similar to how `claude /continue` lists sessions for that project). Override with `--scope=[user|project|local]` — default is 'project'. + +## Summary of Changes + +Added `SessionScope` enum (`Project` | `User`) to `src/cli.rs`. +Added `--scope` flag to `SessionsCmd::List` with default `project`. +Updated `sessions::list()` signature to accept `scope: SessionScope`. +When scope is `Project`, resolves the current working directory and filters raw rows to only include sessions whose `project_path` exactly matches the CWD. Scope `User` shows all sessions (previous behavior). diff --git a/src/cli.rs b/src/cli.rs index 82326a7..1c55e87 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -91,6 +91,16 @@ impl Limit { } } +/// Controls which sessions are shown in `sessions list`. +#[derive(Debug, Clone, Default, clap::ValueEnum)] +pub enum SessionScope { + /// Show only sessions for the current project directory (default). + #[default] + Project, + /// Show all sessions for the current user. + User, +} + /// Top-level CLI entry point for claudbg. #[derive(Debug, clap::Parser)] #[command(name = "claudbg", about = "Claude Code session inspector")] @@ -189,6 +199,9 @@ pub enum SessionsCmd { /// Example: --filter 'model:haiku' --filter 'agents>0' #[arg(long, action = clap::ArgAction::Append)] filter: Vec, + /// Scope of sessions to show: 'project' (current dir only, default) or 'user' (all). + #[arg(long, default_value = "project")] + scope: SessionScope, }, /// Dump raw messages from a session. Dump { diff --git a/src/commands/sessions.rs b/src/commands/sessions.rs index be995c8..89599ed 100644 --- a/src/commands/sessions.rs +++ b/src/commands/sessions.rs @@ -222,6 +222,7 @@ impl crate::filter::SessionRow for RawSessionRow { pub async fn list( limit: crate::cli::Limit, filters: Vec, + scope: crate::cli::SessionScope, opts: &crate::cli::GlobalOpts, ) -> Result<()> { // Parse all filter expressions up front so we can report errors immediately. @@ -230,6 +231,14 @@ pub async fn list( .map(|s| crate::filter::Filter::parse(s)) .collect::>>()?; + // Resolve project scope: current working directory when scope == Project. + let project_cwd: Option = match scope { + crate::cli::SessionScope::Project => std::env::current_dir() + .ok() + .map(|p| p.to_string_lossy().into_owned()), + crate::cli::SessionScope::User => None, + }; + let db_path = crate::db::connection::default_db_path(); let db = crate::db::connection::open_db(&db_path, false).await?; @@ -290,6 +299,16 @@ pub async fn list( }); } + // Apply project scope: only show sessions whose project_path matches CWD. + let raw_rows: Vec = if let Some(ref cwd) = project_cwd { + raw_rows + .into_iter() + .filter(|r| &r.project_path == cwd) + .collect() + } else { + raw_rows + }; + // Apply filters (AND semantics: all filters must match). let raw_rows: Vec = raw_rows .into_iter() @@ -783,7 +802,13 @@ mod tests { // SAFETY: single-threaded test context; no other threads read HOME concurrently. unsafe { std::env::set_var("HOME", dir.path()) }; let opts = default_opts(); - let result = list(crate::cli::Limit::default(), vec![], &opts).await; + let result = list( + crate::cli::Limit::default(), + vec![], + crate::cli::SessionScope::User, + &opts, + ) + .await; assert!(result.is_ok(), "list failed: {:?}", result.err()); } @@ -799,7 +824,13 @@ mod tests { output: OutputFormat::Json, ..default_opts() }; - let result = list(crate::cli::Limit::default(), vec![], &opts).await; + let result = list( + crate::cli::Limit::default(), + vec![], + crate::cli::SessionScope::User, + &opts, + ) + .await; assert!(result.is_ok(), "list json failed: {:?}", result.err()); } @@ -815,7 +846,13 @@ mod tests { output: OutputFormat::Xml, ..default_opts() }; - let result = list(crate::cli::Limit::default(), vec![], &opts).await; + let result = list( + crate::cli::Limit::default(), + vec![], + crate::cli::SessionScope::User, + &opts, + ) + .await; assert!(result.is_ok(), "list xml failed: {:?}", result.err()); } diff --git a/src/main.rs b/src/main.rs index e2dec80..cb95e4a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,23 @@ //! claudbg binary entry point. use clap::Parser; -use claudbg::cli::{AgentsCmd, Cli, Commands, SessionsCmd}; +use claudbg::cli::{AgentsCmd, Cli, Commands, SessionScope, SessionsCmd}; use claudbg::error::Result; #[tokio::main] async fn main() -> Result<()> { let cli = Cli::parse(); match cli.command { - Commands::Sessions { cmd } => match cmd.unwrap_or(SessionsCmd::List { limit: Default::default(), filter: vec![] }) { - SessionsCmd::List { limit, filter } => claudbg::commands::sessions::list(limit, filter, &cli.global).await?, + Commands::Sessions { cmd } => match cmd.unwrap_or(SessionsCmd::List { + limit: Default::default(), + filter: vec![], + scope: SessionScope::Project, + }) { + SessionsCmd::List { + limit, + filter, + scope, + } => claudbg::commands::sessions::list(limit, filter, scope, &cli.global).await?, SessionsCmd::Dump { id, follow } => { claudbg::commands::sessions::dump(&id, follow, &cli.global).await? } @@ -18,9 +26,11 @@ async fn main() -> Result<()> { } }, Commands::Agents { cmd } => match cmd { - AgentsCmd::List { session_id, limit, filter } => { - claudbg::commands::agents::list(&session_id, limit, filter, &cli.global).await? - } + AgentsCmd::List { + session_id, + limit, + filter, + } => claudbg::commands::agents::list(&session_id, limit, filter, &cli.global).await?, AgentsCmd::Dump { session_id, agent_id,