use std::path::{Path, PathBuf};
use recall_hooks::{exit, PromoteError, PromoteTarget};
use crate::project;
#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]
pub enum Target {
Global,
Machine,
}
impl From<Target> for PromoteTarget {
fn from(t: Target) -> Self {
match t {
Target::Global => PromoteTarget::Global,
Target::Machine => PromoteTarget::Machine,
}
}
}
pub async fn run(file: &Path, to: Target) -> anyhow::Result<i32> {
let ctx = project::resolve().hook_context()?;
let path = resolve(&ctx.memory_dir, file);
match recall_hooks::promote(&ctx, &path, to.into()).await {
Ok(res) => {
if res.resumed {
println!(
"recall: finished an earlier promotion of {}, it was already in {}",
res.from, res.to
);
} else {
println!("recall: promoted {} → {}", res.from, res.to);
}
match to {
Target::Global => {
if let Some(global) = ctx.global() {
println!(
"
It is stored under {} and linked from MEMORY.md. Every other project
picks it up at its next session start, when the pull hook runs.",
global.key
);
}
}
Target::Machine => {
if let Some(machine) = ctx.machine() {
println!(
"
It is stored under {} and linked from MEMORY.md. It follows this machine
into every project here, and reaches no other machine.",
machine.key
);
}
}
}
Ok(exit::OK)
}
Err(err) => {
eprintln!("recall: {err}");
Ok(match err {
PromoteError::Sync(_) => exit::SERVER,
_ => exit::CONFIG,
})
}
}
}
fn resolve(memory_dir: &Path, file: &Path) -> PathBuf {
if file.is_absolute() {
return file.to_path_buf();
}
memory_dir.join(file)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_relative_note_is_looked_for_in_the_memory_directory() {
let dir = Path::new("/home/me/.claude/projects/-home-me-app/memory");
assert_eq!(
resolve(dir, Path::new("topics/user.md")),
dir.join("topics/user.md")
);
}
#[test]
fn an_absolute_note_is_taken_as_given() {
let given = Path::new("/home/me/.claude/projects/-home-me-app/memory/user.md");
assert_eq!(resolve(Path::new("/somewhere/else"), given), given);
}
#[test]
fn a_traversing_path_still_reads_as_traversing_after_the_join() {
let dir = Path::new("/home/me/memory");
assert_eq!(
resolve(dir, Path::new("../../.ssh/id_rsa")),
Path::new("/home/me/memory/../../.ssh/id_rsa")
);
}
}