Skip to main content

engram_core/
cli.rs

1use std::path::PathBuf;
2use std::sync::Arc;
3
4use serde_json::Value;
5
6use crate::config;
7use crate::dispatch;
8use crate::error::CoreError;
9use crate::lock_helpers;
10use crate::output::{OutputFormat, format_output};
11use crate::persistence;
12use crate::server::{
13    ServerState, check_legacy_database, initialize_state, resolve_index_directory,
14};
15
16pub async fn execute(
17    state: Arc<ServerState>,
18    method: &str,
19    params: Value,
20    format: &OutputFormat,
21) -> Result<(), CoreError> {
22    let result = dispatch::route(method, &state, params).await?;
23    let formatted = format_output(&result, format);
24    println!("{formatted}");
25    save_indexes_if_mutating(method, &state)?;
26    Ok(())
27}
28
29pub fn build_state(config: &crate::config::Config) -> Result<Arc<ServerState>, CoreError> {
30    let cwd = std::env::current_dir()
31        .map_err(|error| CoreError::InitFailed(format!("cwd unavailable: {error}")))?;
32    let home = home_dir_or_error()?;
33    build_state_with_dirs(config, &cwd, &home)
34}
35
36pub fn build_state_with_dirs(
37    config: &crate::config::Config,
38    cwd: &std::path::Path,
39    home_dir: &std::path::Path,
40) -> Result<Arc<ServerState>, CoreError> {
41    let project_dir = match config::resolve_project_dir(cwd, None) {
42        Ok(path) => path,
43        Err(CoreError::ProjectDirNotFound) => {
44            return Err(CoreError::InitFailed(
45                "no .engram/ directory found in cwd or ancestors — run 'engram init' in your project root".into(),
46            ));
47        }
48        Err(other) => return Err(other),
49    };
50    check_legacy_database(&project_dir, home_dir)?;
51    let state = initialize_state(config, &project_dir, home_dir)?;
52    Ok(Arc::new(state))
53}
54
55fn home_dir_or_error() -> Result<PathBuf, CoreError> {
56    match std::env::var("HOME") {
57        Ok(value) if !value.is_empty() => Ok(PathBuf::from(value)),
58        _ => Err(CoreError::InitFailed(
59            "HOME environment variable not set".into(),
60        )),
61    }
62}
63
64fn save_indexes_if_mutating(method: &str, state: &Arc<ServerState>) -> Result<(), CoreError> {
65    let mutating = matches!(
66        method,
67        "memory_store"
68            | "memory_consolidate_apply"
69            | "memory_import"
70            | "memory_insights"
71            | "memory_migrate_apply"
72            | "memory_train_generate"
73            | "memory_train_delete"
74            | "memory_reembed"
75    );
76    if !mutating {
77        return Ok(());
78    }
79    let index_directory = resolve_index_directory(&state.database_path);
80    let indexes = lock_helpers::read_indexes(state);
81    persistence::save_to_disk(&index_directory, &indexes)
82}