spool-memory 0.2.3

Local-first developer memory system — persistent, structured knowledge for AI coding tools
Documentation
//! 桌面 facade 的输入校验集合。

use super::dto::{
    DesktopMemoryActionRequest, DesktopMemoryDraftRequest, DesktopRecordLookupRequest,
    DesktopRouteRequest, DesktopSessionActionRequest, DesktopSessionDetailRequest,
};
use crate::app;
use std::fs;
use std::path::Path;

pub(super) fn validate_route_request(request: &DesktopRouteRequest) -> Result<(), String> {
    validate_route_inputs(
        request.config_path.as_path(),
        request.cwd.as_path(),
        &request.task,
        request.vault_root_override.as_deref(),
    )
}

pub(super) fn validate_route_inputs(
    config_path: &Path,
    cwd: &Path,
    task: &str,
    vault_root_override: Option<&Path>,
) -> Result<(), String> {
    validate_config_path(config_path)?;
    validate_cwd(cwd)?;
    if task.trim().is_empty() {
        return Err("请先填写 Task,至少用一句话说明你要什么上下文。".to_string());
    }
    if let Some(vault_root_override) = vault_root_override {
        let resolved_override = app::resolve_override_path(vault_root_override, config_path)
            .map_err(|error| format!("vault root 覆盖路径解析失败:{error}"))?;
        match fs::metadata(&resolved_override) {
            Ok(metadata) if metadata.is_dir() => {}
            Ok(_) => {
                return Err(format!(
                    "vault root 覆盖路径不是目录:{}",
                    resolved_override.display()
                ));
            }
            Err(_) => {
                return Err(format!(
                    "vault root 覆盖路径不存在:{}",
                    resolved_override.display()
                ));
            }
        }
    }
    Ok(())
}

pub(super) fn validate_config_path(config_path: &Path) -> Result<(), String> {
    if config_path.as_os_str().is_empty() {
        return Err("请先填写 Config 路径。".to_string());
    }
    if !config_path.exists() {
        return Err(format!("Config 不存在:{}", config_path.display()));
    }
    if !config_path.is_file() {
        return Err(format!("Config 不是文件:{}", config_path.display()));
    }
    Ok(())
}

fn validate_cwd(cwd: &Path) -> Result<(), String> {
    if cwd.as_os_str().is_empty() {
        return Err("请先填写 CWD。".to_string());
    }
    if !cwd.exists() {
        return Err(format!("CWD 不存在:{}", cwd.display()));
    }
    if !cwd.is_dir() {
        return Err(format!("CWD 不是目录:{}", cwd.display()));
    }
    Ok(())
}

pub(super) fn validate_record_lookup_request(
    request: &DesktopRecordLookupRequest,
) -> Result<(), String> {
    validate_config_path(request.config_path.as_path())?;
    if request.record_id.trim().is_empty() {
        return Err("请先填写 record_id。".to_string());
    }
    Ok(())
}

pub(super) fn validate_memory_draft_request(
    request: &DesktopMemoryDraftRequest,
) -> Result<(), String> {
    validate_config_path(request.config_path.as_path())?;
    if request.title.trim().is_empty() {
        return Err("请先填写记忆标题。".to_string());
    }
    if request.summary.trim().is_empty() {
        return Err("请先填写记忆摘要。".to_string());
    }
    if request.memory_type.trim().is_empty() {
        return Err("请先填写 memory_type。".to_string());
    }
    if request.source_ref.trim().is_empty() {
        return Err("请先填写 source_ref。".to_string());
    }
    Ok(())
}

pub(super) fn validate_memory_action_request(
    request: &DesktopMemoryActionRequest,
) -> Result<(), String> {
    validate_config_path(request.config_path.as_path())?;
    if request.record_id.trim().is_empty() {
        return Err("请先填写 record_id。".to_string());
    }
    Ok(())
}

pub(super) fn validate_session_detail_request(
    request: &DesktopSessionDetailRequest,
) -> Result<(), String> {
    validate_config_path(request.config_path.as_path())?;
    if request.session_id.trim().is_empty() {
        return Err("请先填写 session_id。".to_string());
    }
    Ok(())
}

pub(super) fn validate_session_action_request(
    request: &DesktopSessionActionRequest,
) -> Result<(), String> {
    validate_config_path(request.config_path.as_path())?;
    if request.session_id.trim().is_empty() {
        return Err("请先填写 session_id。".to_string());
    }
    Ok(())
}