Skip to main content

dejavu/cli/
mod.rs

1//! CLI dispatch and the shared application context.
2
3pub mod dejavu_cli;
4
5use crate::commands::render;
6use crate::config::Config;
7use crate::env::{self, AgentEnv};
8use crate::paths::CacheLayout;
9use crate::{repo, state};
10use dejavu_cli::{Cli, DejavuCmd};
11use std::path::PathBuf;
12
13/// Resolved context every command needs: the repo, its cache layout, the
14/// effective config, and the active session id (if any).
15pub struct AppCtx {
16    pub cwd: PathBuf,
17    pub repo_root: PathBuf,
18    pub layout: CacheLayout,
19    pub config: Config,
20    pub session_id: Option<String>,
21}
22
23impl AppCtx {
24    pub fn resolve() -> anyhow::Result<AppCtx> {
25        let cwd = std::env::current_dir()?;
26        let (repo_root, layout) = if let Some(agent) = AgentEnv::from_current() {
27            // Inside a session: trust the launcher's repo + cache dir.
28            (
29                agent.repo_root.clone(),
30                CacheLayout::from_dir(agent.cache_dir.clone()),
31            )
32        } else {
33            let root = repo::detect_repo_root(&cwd);
34            let layout = CacheLayout::for_repo(&root)?;
35            (root, layout)
36        };
37        let config = Config::load(&repo_root)?;
38        let session_id = std::env::var(env::SESSION_ID).ok();
39        Ok(AppCtx {
40            cwd,
41            repo_root,
42            layout,
43            config,
44            session_id,
45        })
46    }
47
48    pub fn repo_root_str(&self) -> String {
49        self.repo_root.to_string_lossy().into_owned()
50    }
51}
52
53/// Dispatch a parsed `dejavu` command to its handler. Returns the process exit
54/// code. Note: the `Run` path is handled directly in `bin/dejavu.rs` (it needs
55/// the exit-code guard) and never reaches here.
56pub fn run(cli: Cli) -> anyhow::Result<i32> {
57    match cli.command {
58        DejavuCmd::Start { command } => crate::agent::launch(command),
59        DejavuCmd::Init => crate::commands::init::run(),
60        DejavuCmd::Shellenv {
61            install,
62            uninstall,
63            shell,
64        } => crate::commands::shellenv::run(install, uninstall, shell),
65        DejavuCmd::Stats { json, all, public } => crate::commands::stats::run(json, all, public),
66        DejavuCmd::Repos { json, all } => crate::commands::repos::run(json, all),
67        DejavuCmd::Report { redact } => crate::commands::stats::report(redact),
68        DejavuCmd::Enable => set_repo_disabled(false),
69        DejavuCmd::Disable => set_repo_disabled(true),
70        DejavuCmd::Run { shim_name, args } => crate::runtime::run_shim(&shim_name, &args),
71        DejavuCmd::Show {
72            target,
73            stdout,
74            stderr,
75            normalized,
76        } => crate::commands::show::run(&target, stdout, stderr, normalized),
77        DejavuCmd::Grep {
78            target,
79            pattern,
80            normalized,
81        } => crate::commands::grep::run(&target, &pattern, normalized),
82        DejavuCmd::Doctor { json } => crate::commands::doctor::run(json),
83        DejavuCmd::Bench {
84            scenario,
85            json,
86            check,
87        } => crate::commands::bench::run(scenario, json, check),
88        DejavuCmd::Clean { older_than, all } => crate::commands::clean::run(older_than, all),
89        DejavuCmd::Uninstall => crate::commands::clean::uninstall(),
90    }
91}
92
93fn set_repo_disabled(disabled: bool) -> anyhow::Result<i32> {
94    let ctx = AppCtx::resolve()?;
95    ctx.layout.ensure_dirs()?;
96    let mut st = state::load(&ctx.layout);
97    st.disabled = disabled;
98    state::save(&ctx.layout, &st)?;
99    render::title(if disabled {
100        "Dejavu disabled"
101    } else {
102        "Dejavu enabled"
103    });
104    render::kv(&[("Repo", ctx.repo_root.display().to_string())]);
105    Ok(0)
106}